文章目录
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
思路:
采用切分-反转-合并三步解法,复用链表基础操作,时间复杂度O(n),空间复杂度O(1)。
- 快慢指针找中点 :将链表切分为前后两段,奇数长度时
前半段多一个节点。 - 反转后半段链表 :解决单链表无法反向遍历的问题。
反转链表 - 交叉合并两段链表:按前半段节点、后半段节点的顺序交替拼接。
示例1(偶数节点:1→2→3→4)
-
切分:前半段
1→2,后半段3→4 -
反转后半段:
4→3 -
合并结果:
1→4→2→3
示例2(奇数节点:1→2→3→4→5)
-
切分:前半段
1→2→3,后半段4→5 -
反转后半段:
5→4 -
合并结果:
1→5→2→4→3
代码实现(Go):
go
package main
import "fmt"
// ListNode 定义单链表节点结构
type ListNode struct {
Val int
Next *ListNode
}
// reorderList 重排链表主函数
// 要求:L0→Ln→L1→Ln-1→L2→Ln-2→...
func reorderList(head *ListNode) {
// 边界条件:空链表或只有一个节点,无需处理
if head == nil || head.Next == nil {
return
}
// 1. 快慢指针寻找链表中点,并切分链表
slow, fast := head, head.Next
// 快指针走到末尾时,慢指针到达中点
// 因为 fast 每次走两步,所以必须保证 fast 和 fast.Next 都不为 nil,避免空指针访问
for fast != nil && fast.Next != nil {
slow = slow.Next
fast = fast.Next.Next
}
// 切分得到后半段头节点
rightHead := slow.Next
// 断开前后两段,形成独立链表
slow.Next = nil
// 2. 反转后半段链表
rightHead = reverseList(rightHead)
// 3. 交叉合并前后两段链表
mergeList(head, rightHead)
}
// reverseList 反转单链表,返回反转后的头节点
func reverseList(head *ListNode) *ListNode {
var prev *ListNode // 前驱节点,初始为nil
cur := head // 当前遍历节点
for cur != nil {
next := cur.Next // 保存下一个节点
cur.Next = prev // 反转当前节点指向
prev = cur // 前驱节点后移
cur = next // 当前节点后移
}
// prev 最终指向反转后的头节点
return prev
}
// mergeList 交叉合并两个链表 l1 和 l2
// 合并规则:l1 节点 -> l2 节点 -> l1 节点 -> l2 节点...
func mergeList(l1, l2 *ListNode) {
for l1 != nil && l2 != nil {
// 暂存两个链表的下一个节点,防止断链
next1, next2 := l1.Next, l2.Next
// 执行交叉拼接
l1.Next = l2
l2.Next = next1
// 两个链表指针同步后移
l1, l2 = next1, next2
}
}
func main() {
// ========== 测试用例 1:偶数个节点 1->2->3->4 ==========
// 构建链表:1 -> 2 -> 3 -> 4
head1 := &ListNode{
Val: 1,
Next: &ListNode{
Val: 2,
Next: &ListNode{
Val: 3,
Next: &ListNode{Val: 4}, // 默认 Next=nil,表示尾节点
},
},
}
// 调用重排函数:变成 1->4->2->3
reorderList(head1)
// 遍历输出链表
for cur := head1; cur != nil; cur = cur.Next {
fmt.Print(cur.Val)
if cur.Next != nil {
fmt.Print("->") // 控制输出格式
}
}
fmt.Println()
// ========== 测试用例 2:奇数个节点 1->2->3->4->5 ==========
// 构建链表:1 -> 2 -> 3 -> 4 -> 5
head2 := &ListNode{
Val: 1,
Next: &ListNode{
Val: 2,
Next: &ListNode{
Val: 3,
Next: &ListNode{
Val: 4,
Next: &ListNode{Val: 5}, // 尾节点
},
},
},
}
// 调用重排函数:变成 1->5->2->4->3
reorderList(head2)
// 遍历输出链表
for cur := head2; cur != nil; cur = cur.Next {
fmt.Print(cur.Val)
if cur.Next != nil {
fmt.Print("->")
}
}
}
- 时间复杂度 :O(n),仅遍历链表常数次。
- 空间复杂度 :O(1),仅使用常数级指针变量。