funcswapPairs(head *ListNode) *ListNode { if head == nil || head.Next == nil { return head } // 递归结束条件 next := head.Next head.Next = swapPairs(next.Next) next.Next = head // 两两互换,调用递归 return next }
解二 迭代
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
funcswapPairs2(head *ListNode) *ListNode { dummy := &ListNode{0, head} pre := dummy for head != nil && head.Next != nil { first := head second := head.Next // pre -> first -> second -> ... pre.Next = second first.Next = second.Next second.Next = first // pre -> second -> first -> ... pre = first head = first.Next // 更新迭代 } return dummy.Next }
25.K个一组翻转链表
给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。
k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
示例 1:
1 2
输入:head = [1,2,3,4,5], k = 2 输出:[2,1,4,3,5]
示例 2:
1 2
输入:head = [1,2,3,4,5], k = 3 输出:[3,2,1,4,5]
思路:
直接对每n个为一段,执行翻转
最后一次计数达不到n时直接返回
共用辅助函数 翻转链表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// 辅助函数:翻转链表 // 反转从 head 到 tail 之间的节点 // 不包含 tail 节点 // @return 反转后的头节点 funcreverseListReturnHead(head, tail *ListNode) *ListNode { var prev *ListNode cur := head for cur != tail { next := cur.Next cur.Next = prev prev = cur cur = next } return prev }
解一 递归
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
funcreverseKGroup(head *ListNode, k int) *ListNode { // 检查是否有足够的节点 cur := head for i := 0; i < k; i++ { if cur == nil { return head } cur = cur.Next } // 翻转前 k 个节点 newHead := reverseListReturnHead(head, cur) // 递归翻转剩余的节点 head.Next = reverseKGroup(cur, k) return newHead }
funcreverseKGroup2(head *ListNode, k int) *ListNode { dummy := &ListNode{0, head} pre := dummy for head != nil { tail := pre for i := 0; i < k; i++ { tail = tail.Next if tail == nil { return dummy.Next } } next := tail.Next newHead := reverseListReturnHead(head, next) // 反转从 head 到 tail.Next 之间的节点 pre.Next = newHead // pre 指向反转后链表的头节点 head.Next = next // 反转后原 head 变为尾节点,连接到 next pre = head // pre 移动到下一组的前一个节点 head = next // head 移动到下一组的头节点 } return dummy.Next }
138.随机链表的复制
给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。
构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。
例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。
返回复制链表的头节点。
用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:
funccopyRandomList(head *Node) *Node { if head == nil { returnnil } // 用于存储原节点和新节点的映射关系 nodeMap := make(map[*Node]*Node)
// 第一次遍历,创建新节点并存储映射关系 cur := head for cur != nil { nodeMap[cur] = &Node{Val: cur.Val} cur = cur.Next }
// 第二次遍历,为新节点的 Next 和 Random 指针赋值 cur = head for cur != nil { if cur.Next != nil { nodeMap[cur].Next = nodeMap[cur.Next] } if cur.Random != nil { nodeMap[cur].Random = nodeMap[cur.Random] } cur = cur.Next }
funccopyRandomList2(head *Node) *Node { if head == nil { returnnil } // 第一次遍历,复制节点并插入到原节点的后面 cur := head for cur != nil { newNode := &Node{Val: cur.Val, Next: cur.Next} cur.Next = newNode cur = newNode.Next }
// 第二次遍历,设置新节点的 Random 指针 cur = head for cur != nil { if cur.Random != nil { cur.Next.Random = cur.Random.Next } cur = cur.Next.Next }
// 第三次遍历,拆分链表 cur = head newHead := head.Next newCur := newHead for cur != nil { cur.Next = newCur.Next cur = cur.Next if cur != nil { newCur.Next = cur.Next newCur = newCur.Next } } return newHead }
148.排序链表
给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
示例 1:
1 2
输入:head = [4,2,1,3] 输出:[1,2,3,4]
示例 2:
1 2
输入:head = [-1,5,3,4,0] 输出:[-1,0,3,4,5]
示例 3:
1 2
输入:head = [] 输出:[]
常用的冒泡 插入时间上都无法满足
考虑归并处理
解一 递归 自顶向下
感觉这个方式好理解些
mergeTwoList(left,right)为之前写过的合并有序链表操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
if head == nil || head.Next == nil { return head } // 快慢指针找到链表的中间节点 slow, fast := head, head.Next for fast != nil && fast.Next != nil { slow = slow.Next fast = fast.Next.Next } // 断开链表 mid := slow.Next slow.Next = nil // 递归排序左右子链表 left := sortList(head) right := sortList(mid)
// Put 向缓存中添加一个元素 func(c *LRUCache) Put(key int, value int) { // 如果元素已经存在,更新值并移动到链表头部 if node, ok := c.items[key]; ok { node.val = value c.evictList.moveToFront(node) return }
// Get 从缓存中获取一个元素 func(c *LRUCache) Get(key int) int { if node, ok := c.items[key]; ok { // 访问后将节点移动到链表头部 c.evictList.moveToFront(node) return node.val } return-1// 如果元素不存在,返回-1 }