25.k个一组翻转链表
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例 :
给定这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
说明 :
你的算法只能使用常数的额外空间。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
Python most votes solution:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def reverseKGroup(self, head, k):
"""
:type head: ListNode
:type k: int
:rtype: ListNode
"""
dummy = jump = ListNode(0)
dummy.next = l = r = head
while True:
count = 0
while r and count < k: # use r to locate the range
r = r.next
count += 1
if count == k: # if size k satisfied, reverse the inner linked list
pre, cur = r, l
for _ in range(k):
cur.next, cur, pre = pre, cur.next, cur # standard reversing
jump.next, jump, l = pre, l, r # connect two k-groups
else:
return dummy.next
分析:
-
在指针的移动过程中要注意三点:
第1点:
等号左边的next表示指向,右边的next表示位置。即:
a)等号左边若有next,则表示等号左边的指针将指向等号右边的位置。如:
first.next = second.next
表示first将指向second的下一个位置,如图:
b)等号左边若无next,则表示等号左边的指针将移动到等号右边的位置。如:
first = second.next
表示first将移动到second的下一个位置,如图:
c)等号右边若有next,则表示等号右边指针的后面的位置。如b)中的例子所示。
d)等号右边若无next,则表示等号右边指针的当前位置。如:
first = second
表示first将移动到second的位置处。如图:
第2点:
代码的写法不同,指针的移法也不同,可以分为“同步”移法和“异步”移法。
(1)“异步”移法:代码中指针的移动是有先后顺序的。“异步”移动时,每一步的移动都是基于上一步的移动结果进行的,即在前一步的移动结果确定之后,才能进行当前步的移动。这种移法比较好理解,详见第0024题的分析。
(2)“同步”移法:指针的移动是按“组”完成的,同组内的指针是同时移动的。“同步”移动时,同组内各指针的移动互不干扰,每个指针的移动都只基于这一组指针的初始状态,而与其他指针的状态无关。本例中的代码使用的就是这种移动方法,以下将具体分析本题中各指针的移动过程。
假设k=3,则在第一个外层while循环的过程中,各指针的移动过程如下图所示(粉红色框表示第一个group,绿色框表示第二个group):
第二个及以后的while循环中,指针的移动过程均和上面类似。
算法处理最后几个不够k个一组的元素是通过条件
if count == k
来判断的。
第3点:
在指针移动的过程中,如果指向某节点的指针始终都没有移动(如指向节点a的指针head),则不管a节点本身如何移动,head指针都会始终指向a节点。在for循环的第三轮结束时,尽管节点a已经发生了很多变动,但jump.next始终都会指向该节点,直到jump指针本身发生变化。