0x01.问题
给你一个链表,每
k
个节点一组进行翻转,请你返回翻转后的链表。
k
是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是k
的整数倍,那么请将最后剩余的节点保持原有顺序。
你的算法只能使用常数的额外空间。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
输入示例:1->2->3->4->5 k = 3
输出示例:3->2->1->4->5
C++结构体:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
C++函数形式:ListNode* reverseKGroup(ListNode* head, int k)
这个问题实质上是这个问题的升级: 两两交换链表中的节点
建立在这个问题的基础上:反转链表
0x02.简要分析
这又是一个逆转链表的问题,不过它的不同在于是分组逆转,按指定的组来逆转链表。
这其实也并不是一个棘手的问题,因为我们已经有翻转链表的思路,我们只需要把它们分下组就行了。
怎么分组呢?
首先,我们需要确定会造成哪些影响,除了每一个组内部的结构改变了,这个组的前面一个指针的指向其实也发生了改变,而且因为我们使用的是翻转的思路,所以反转后,这个链表的尾部为空,所以我们还需要把它的指向改变。我们还需要一个指针来不断的更新分组的位置。
基于上述思路,我们需要两个指针,一个pre
,始终指向当前分组的前一个节点,一个end
,控制分组的位置。
我们的具体思路是:
end
指针每次移动k
个位置,确定分组的尾部,如果没有移动k
个位置就到末尾了,说明最后那一组不用逆转。- 使用一个指针
next
来保存end
的指向。 - 使用一个指针
start
来记录每一个组的开头,它应该等于pre->next
。 - 将
end
指针的指向改为NULL
,因为要传进函数去逆转,所以需要截断。 - 让
pre->next
等于逆转后的头指针。 - 让
start
的指向指向next
,因为此时start
已经是这个分组的尾部了。 - 更新
pre
为start
。 - 跟新
end
为pre
。 - 不断迭代,直到
end
是最后一个元素。
具体逆转思路,请参考 : 反转链表–两种思路
0x03.解决代码–分组逆转
class Solution {
public:
ListNode*reverse(ListNode*head){
ListNode*pre=NULL;
ListNode*curr=head;
while(curr){
ListNode*next=curr->next;
curr->next=pre;
pre=curr;
curr=next;
}
return pre;
}
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode*dummy=new ListNode(0);
dummy->next=head;
ListNode*pre=dummy;
ListNode*end=dummy;
while(end->next){
for(int i=0;i<k&&end;i++) end=end->next;
if(!end) break;
ListNode*next=end->next;
ListNode*start=pre->next;
end->next=NULL;
pre->next=reverse(start);
start->next=next;
pre=start;
end=pre;
}
return dummy->next;
}
};
ATFWUS --Writing By 2020–03–24