题目描述
给定一个单链表 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 * 104] 1 <= node.val <= 1000
思路
思路1 链表法
将整个链表分成前后两个部分,将后面部分逆置后,和前面部分重新链接在一起,核心算法包括
- 使用快慢指针寻找中间节点前驱的算法
- 反转链表的算法
- 重新链接两个链表的算法
代码
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func reorderList(head *ListNode) {
var midNode, head2 *ListNode
midNode = findMidNode(head)
head2 = midNode.Next
midNode.Next = nil
head2 = reverse(head2)
var next1, next2 *ListNode
for head != nil && head2 != nil {
next1, next2 = head.Next, head2.Next
head.Next = head2
head2.Next = next1
head = next1
head2 = next2
}
}
func reverse(head *ListNode) *ListNode {
var pre *ListNode
for head != nil {
next := head.Next
head.Next = pre
pre= head
head = next
}
return pre
}
func findMidNode(node *ListNode) *ListNode {
var slow, fast *ListNode
slow, fast = node, node
for fast != nil && fast.Next != nil {
slow = slow.Next
fast = fast.Next.Next
}
return slow
}
图示
思路2
思考:本题思路还是比较清晰的,但是链表不支持随机访问,只能顺序访问。所以我们想着能不能将其转换为支持顺序访问的形式,于是我们就有了:将链表形式转换为线性表形式的想法。
使用一个辅助数组,将链表转换为数组,通过下标直接访问完成指针的重新指向,以完成链表的重排。
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func reorderList(head *ListNode) {
var nodes []*ListNode
for head != nil {
nodes = append(nodes, head)
head = head.Next
}
var i, j int
for i, j = 0, len(nodes)-1; i < j; i, j = i+1, j-1 {
nodes[i].Next = nodes[j]
if i+1 == j { // 不能指向自己
break
}
nodes[j].Next = nodes[i+1]
}
nodes[j].Next = nil
}