leetcode 25. K 个一组翻转链表
xxleyi opened this issue · comments
题:
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例:
给你这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
说明:
你的算法只能使用常数的额外空间。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-nodes-in-k-group
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解:
此题难度被 leetcode 认定为 hard,但粗略读过问题之后,发现解题思路并不复杂,只是细节会比较多。
细节多主要体现在维持「循环不变式」需要的变量较多。最终实现之后,我使用了 6 个变量,且没有发现可以精简的余地。
除此之外,还需要在头部和尾部,根据特定的条件进行特殊处理,这也算是细节多的一部分。
如果还要再加一点,就是最后一段无法整除,也就是不足 k 个节点时该如何处理的细节。思路是再次翻转过来,但如果不考虑的多一点,很可能会另写一个单独的逻辑。但稍加考虑之后会发现,可以很好的复用已经写好的逻辑。
这道题很贴近实际工作的任务:思路不难,比较直接,但涉及变量较多,细节上的处理容易出漏洞,逻辑容易陷入混乱和冗余。
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @param {number} k
* @return {ListNode}
*/
var reverseKGroup = function(head, k) {
let i = 0
let cur = head
let prev = null
let prevSegmentTail = null
let curSegmentTail = head
let newHead = null
while (cur) {
if (i < k) {
i++
const oldPrev = prev
const curNext = cur.next
prev = cur
prev.next = oldPrev
cur = curNext
}
else {
// 单独处理 newHead
!newHead && (newHead = prev)
// prevSegmentTail 为空时也需要单独处理
prevSegmentTail && (prevSegmentTail.next = prev)
prevSegmentTail = curSegmentTail
curSegmentTail = cur
prev = null
i = 0
}
}
if (i === k) {
// 恰好整除时的处理
// 多过一段的处理
if (prevSegmentTail) prevSegmentTail.next = prev
// 只有一段的处理
else newHead = prev
} else {
// 非整除部分的处理:复用已有逻辑,再次翻转过来,达到负负为正的目的
prevSegmentTail.next = reverseKGroup(prev, i)
}
return newHead
};