依次迭代:设置一个伪头节点 preHead 用于指向返回结果的头节点,并将当前节点 cur 指向 preHead。然后对比两个链表的头节点,将 cur 的next指向更小的节点,并将该链表的头节点指向下一个节点。直到有一个链表为空,将另一个链表的剩余部分拼接到 cur 的next节点即可。最后返回伪头节点的 next 节点。
双指针:first 指针先从链表头节点移动 k 步,然后 second 与 first 指针同时移动,当 first 指针指向链表尾部的时候,second 指针指向的就是链表的倒数第 k 个节点。
寻找和删除倒数第 k 个节点都是相同的思路,下面的代码展示的是删除,不同点在于用了一个 pre 指针指向 second 节点,用于删除要删除的节点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
funcremoveNthFromEnd(head *ListNode, n int) *ListNode { preHead := &ListNode{ Next: head, } first := head for n > 0 { // 第一个节点先移动n步 first = first.Next n-- }
pre, second := preHead, head for first != nil { // 两个节点一起移动,直到first到达链表尾部 pre, second = second, second.Next first = first.Next } pre.Next = second.Next return preHead.Next }
时间复杂度:O(N)
空间复杂度:O(1)
4、寻找单链表的中点
快慢指针:slow 每次移动一步,fast 每次移动两步,当 fast 或者 fast.Next 为空时,slow指针移到了链表的中间节点。
1 2 3 4 5 6 7 8 9 10 11
funcmiddleNode(head *ListNode) *ListNode { if head.Next == nil { return head } slow, fast := head, head for fast != nil && fast.Next != nil { slow = slow.Next fast = fast.Next.Next } return slow }
funcdetectCycle(head *ListNode) *ListNode { if head == nil { returnnil } slow, fast := head, head for fast != nil && fast.Next != nil { slow = slow.Next fast = fast.Next.Next if slow == fast { slow := head // fast指向头节点,然后fast与slow以相同的速度相后移动 for slow != fast { // 当slow与fast再次相遇时,代表找到了环的头节点 slow = slow.Next fast = fast.Next } return fast } } returnnil// 如果链表没有环,会在fast到达结尾时跳出循环,因此在这里返回nil即可 }