题目信息
给你链表的头节点
head,每k个节点一组进行翻转,请你返回修改后的链表。
k是一个正整数,它的值小于或等于链表的长度。如果节点总数不是k的整数倍,那么请将最后剩余的节点保持原有顺序。你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
示例 1:
输入:head = [1,2,3,4,5], k = 2 输出:[2,1,4,3,5]示例 2:
输入:head = [1,2,3,4,5], k = 3 输出:[3,2,1,4,5]示例三
**输入:**head = 1,2,k = 2
输出:2,1
思考过程和自写代码
差不多能够自己写出来了。
核心的逻辑也都放在注释里面了,将k个看成一个区间 / 一组,组内进行反转,然后连接组外(最开始只想到了尾部衔接,导致示例提交出了点问题,手写过程后排查出了问题,嘻嘻,好久没感受过这样的古法编程了....)
耗了一点功夫但是写出来了,唯一迭代的地方注释里面也有了,就是如何处理好示例三的边界(到底什么时候退出反转)
自写满分代码(带注释和思维过程)
python
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
'''
跟上个题目差不多,从2扩充到了一个更大的群体k. 难点在于是否可以复用逻辑;如果可以复用的话,如何复用逻辑
初步想法感觉还是需要把k个数据看作一个整体,而且必然不能和上次一样一个一个去修改
在特定区间内如何反转一段链表,可以参考206反转链表
'''
res = ListNode(0, head)
now_begin = head # 当前区间开始位置
last_tail = res
while now_begin: # k <= n,一定可以进行一次反转的
next_begin = now_begin # next_begin表示下一个需要反转的区间的首个位置
'''
原本代码:
for i in range(k):
next_begin = next_begin.next if next_begin else None # 此时next_begin到达下一个区间需要反转的首个位置
if next_begin is None: break # 当前区间也即不支持反转
后因为示例三做出以下的调整,不能一概而论
'''
for i in range(k):
if not next_begin: return res.next # 先判断再跳转. 执行k次跳转,如果是可以反转的话k次必须都是可以执行的,也就是必须执行k次next_begin = next_begin.next,那么这k次中next_begin必定不是None. 如果next_begin提前进入了none,那就是有问题的(注意不能先跳转再判断,因为我允许next_begin是none,见示例三,此时刚好是k的倍数,允许反转)
next_begin = next_begin.next
pre = None
curr = now_begin
while curr != next_begin:
next_node = curr.next
curr.next = pre #
pre = curr
curr = next_node
now_begin.next = next_begin # 区间尾部衔接,now_begin为当前区间的最后一个数字,指向下一个区间的起点
last_tail.next = pre # 区间首部衔接,上个区间的尾巴指向当前节点的首个数字(如果curr是下一个区间的起点,刚好pre就是原来排列位置当前区间的最后一个 / 现有排列位置的第一个)
last_tail = now_begin # 当前区间的起点反转以后会变成最后一个
now_begin = next_begin
return res.next
代码纯享(复习用)
删去了大段的注释
python
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
res = ListNode(0, head)
now_begin = head # 当前区间开始位置
last_tail = res
while now_begin: # k <= n,一定可以进行一次反转
next_begin = now_begin # next_begin表示下一个需要反转的区间的首个位置
for i in range(k):
if not next_begin: return res.next
next_begin = next_begin.next
pre = None
curr = now_begin
while curr != next_begin:
next_node = curr.next
curr.next = pre
pre = curr
curr = next_node
now_begin.next = next_begin # 区间尾部衔接,now_begin为当前区间的最后一个数字,指向下一个区间的起点
last_tail.next = pre # 区间首部衔接,上个区间的尾巴指向当前节点的首个数字
last_tail = now_begin # 当前区间的起点反转以后会变成最后一个
now_begin = next_begin
return res.next

