K 个一组翻转链表
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例 :
给定这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
说明 :
你的算法只能使用常数的额外空间。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
思路
这个题想了一段时间, 只想出了一种思路,因为递归的那个太复杂,没有想明白,所以没有用递归,只用了几个指针来回的操作即可。 空间复杂度O(1),因为只开辟了一个新链表的头结点的空间,符合题目要求。
思路是这样:
首先,用一个指针p负责遍历一遍链表,指针rear负责指向需要翻转的第一个节点,指针new_rear负责新链表里面,指向翻转组的最后一个节点。
在遍历的时候,会用一个cou当做计数器数节点,如果小于k,p就往后走,如果等于k的时候,p正好指向需要反转的节点的后一个(看下面图中的第一次)。也就是p前面的节点需要逆序,rear指向翻转节点组的第一个节点。也就是rear指向的节点一直到p的前一个节点,都需要逆置到,即用头插法插入到新的链表中即可。插完之后, 要注意翻转完了一组,new_rear要移动最末尾。cou置零
然后p继续往后走,还是按照上面的思路循环。但是当p走到空的时候,此时有两种情况:
- 第一种是cou<k, 也就是说后面的不够一组逆置了,那就不改变顺序,直接把new_rear.next = rear。 连起来即可
- 第二种是cou=k, 正好够一组逆置,这其实是k=元素个数的情况,此时,直接相当于把链表元素逆序。
我给出一幅图吧,因为用的指针有点多,光用文字可能说不太明白, 模拟了一遍k=2时的操作:(重点看看我上面说的那几个指针的指向位置)
下面给出代码:
class Solution:
def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
if not head or not head.next:
return head
# 空链表头结点
new_prehead = ListNode(-1)
new_prehead.next = None
new_rear = new_prehead
p = head
rear = head
cou = 0
while p:
while p and cou < k:
p = p.next
cou = cou + 1
if p:
while rear != p:
q = rear.next
rear.next = new_rear.next
new_rear.next = rear
rear = q
while new_rear.next:
new_rear = new_rear.next
cou = 0
elif cou < k: # p为空的第一种情况直接连上
new_rear.next = rear
else: # p为空的第二种情况直接逆置
while rear:
q = rear.next
rear.next = new_rear.next
new_rear.next = rear
rear = q
return new_prehead.next