1. 题目描述
Leetcode链接 leetcode-cn.com/problems/re…
给你一个链表的头节点 head 。
链表中的节点按顺序划分成若干非空组,这些非空组的长度构成一个自然数序列(1, 2, 3, 4, ...)。一个组的 长度就是组中分配到的节点数目。换句话说:
节点 1 分配给第一组 节点 2 和 3 分配给第二组 节点 4、5 和 6 分配给第三组,以此类推 注意,最后一组的长度可能小于或者等于 1 + 倒数第二组的长度 。
反转每个偶数长度组中的节点,并返回修改后链表的头节点 head 。
输入:head = [5,2,6,3,9,1,7,3,8,4] 输出:[5,6,2,3,9,1,4,8,3,7] 解释:
- 第一组长度为 1 ,奇数,没有发生反转。
- 第二组长度为 2 ,偶数,[2,6]节点反转,变成了[6,2]。
- 第三组长度为 3 ,奇数,没有发生反转。
- 最后一组长度为 4 ,偶数,[7,3,8,4]节点反转, 变成了[4,8,3,7]。
2. 解题思路
需要留意一下题目意思,翻转每一个偶数长度数组,所以如果最后一个数据长度哪怕不是前一个数组长度加1,但也是偶数,那么依旧需要反转。
- 记录上次遍历的数组长度和尾节点。
- 从头节点后面的节点开始遍历。如果遍历的数组长度为上次的数组长度加1,且是偶数,那么执行反转操作,反转完成后拼接链表。继续遍历,直到链表为空。
- 如果最后遍历的数组长度依旧为偶数,那么最后一部分数组执行反转即可。
3. 代码及注释
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func reverseEvenLengthGroups(head *ListNode) *ListNode {
// 空节点或者只有一个头节点,无需处理
if head == nil || head.Next == nil {
return head
}
// cur和lastEnd分别表示当前遍历和上个数组的尾节点
var cur, lastEnd *ListNode = head.Next, head
// 当前数组和上个数组的长度分别为0和1
var count, lastCount int = 0, 1
for cur != nil {
count++
if count == lastCount + 1 {
if count & 1 == 0 {
// 符合条件,执行反转
// 没有记录当前数组的头节点,但可以使用上个数组的尾节点的下一个节点来确定反转的起点
start := lastEnd.Next
// 反转数组,结束点其实就是cur
end := cur.Next
pre := reverse(start, end)
// 上个数组的尾节点指向新数组的头节点
lastEnd.Next = pre
// 因为反转了这个数组,所以cur为这个原始数组的开始节点
cur = start
// 下一个要遍历的节点是下个数组的头节点
cur.Next = end
}
// 标记当前数组的尾节点
lastEnd = cur
// 重新计数
count = 0
lastCount++
}
cur = cur.Next
}
// 最后一个数组,长度还是偶数,依旧要反转
if count & 1 == 0 {
start := lastEnd.Next
// 从start反转到末尾了
pre := reverse(start, nil)
lastEnd.Next = pre
}
return head
}
// 翻转[start, end),翻转start到end前一个位置的链表,并返回end前一个位置作为链表的起始节点
func reverse(start, end *ListNode) *ListNode {
var pre, cur *ListNode= nil, start
for cur != end {
next := cur.Next
cur.Next = pre
pre = cur
cur = next
}
return pre
}