143. 重排链表
给定一个单链表L
的头节点head
,单链表L
表示为:
L0 → L1 → … → Ln - 1 → Ln
请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例 1:
输入:head = [1,2,3,4]
输出:[1,4,2,3]
示例 2:
输入:head = [1,2,3,4,5]
输出:[1,5,2,4,3]
提示:
- 链表的长度范围为 [1, 5 * 10^4]
- 1 <= node.val <= 1000
解题思路
注意
:快慢指针找链表中间节点时,下面这个点很重要!!!
-
链表长度为偶数时,如果用
fast != nil && fast.Next != nil
,则最终slow
停在两个中间元素的后一个。如1 2 3 4
,最后slow
会指着3
。 -
如果用
fast.Next != nil && fast.Next.Next != nil
,则最终slow
停在两个中间元素的前一个,如1 2 3 4
,最后slow
会指着2
。本题我们需要这种情况。
Go代码
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func reorderList(head *ListNode) {
if head == nil || head.Next == nil {
return
}
// 以 1 2 3 4 举例,先将链表拆成两个链表,1 2和3 4
// 然后后一个链表反转变为4 3,最后两个链表合并为 1 4 2 3
// 1. 等分链表,常规套路,快慢指针
slow ,fast := head,head
// 注意:链表长度为偶数时,如果用fast != nil && fast.Next != nil,则最终slow停在两个中间元素的后一个
// 如果用fast.Next != nil && fast.Next.Next != nil,则最终slow停在两个中间元素的前一个,本题我们需要这种情况
for fast.Next != nil && fast.Next.Next != nil {
fast = fast.Next.Next
slow = slow.Next
}
// 切割成两个链表
secondList := slow.Next
slow.Next = nil
// 后一个链表链表反转
secondList = reverseList(secondList)
// 拼接两个链表
slow,fast = head,secondList
for slow != nil && fast != nil {
nxt := slow.Next
secondNxt := fast.Next
slow.Next = fast
fast.Next = nxt
slow = nxt
fast = secondNxt
}
}
func reverseList(head *ListNode) *ListNode {
// 头插法
dummy := &ListNode{}
dummy.Next = head
tail := head
cur := head.Next
for cur != nil {
nxt := cur.Next
cur.Next = dummy.Next
dummy.Next = cur
cur = nxt
tail.Next = nxt
}
return dummy.Next
}