题目如下
Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.
If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.
You may not alter the values in the nodes, only nodes itself may be changed.
Only constant memory is allowed.
For example,
Given this linked list: 1->2->3->4->5
For k = 2, you should return: 2->1->4->3->5
For k = 3, you should return: 3->2->1->4->5
题目的意思是,以K个节点为一个单位,在每个单位内部进行单链表的反转。如果进行到最后,还剩下不到K个节点,那么剩下的节点就不进行反转。也可能是一开始,整个链表就不足K个节点,那么整个链表也不进行反转。
分析如下:
可以老实地迭代进行,每K个为一组,逐组处理,如下面的代码第1版,代码第2版。也可以使用一些改进,比如使用递归,如下面的代码第3版。
我的代码(第1版)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void reverse_range(ListNode* start){ //开始时写成了引用型参数,出错。不仅是没有必要写成引用,而且是必须不能写成引用。
if(start==NULL||start->next==NULL)
return;
ListNode* p=start;
ListNode* q=start->next;
ListNode* r=start->next->next;
while(q!=NULL){
q->next=p;
p=q;
q=r;
if(r!=NULL)
r=r->next;
}
start->next=NULL;
return;
}
ListNode *reverseKGroup(ListNode *head, int k) {
ListNode* p_finish=head;
ListNode* p_start=head;
ListNode* p_pre=NULL;
ListNode* p_next_head=NULL;
ListNode* p_return=NULL;
while(p_start!=NULL) {
int count=k;
while(p_finish->next!=NULL&&count>1){ //记录本段K个节点的头尾
p_finish=p_finish->next;
count--;
}
if(count!=1){//不足K个,不需要reverse
if(p_pre==NULL){
return p_start;
}else{
p_pre->next=p_start;
break;
}
}else{ //足够K个,需要reverse
p_next_head=p_finish->next;记录下一段K个节点的的头
p_finish->next=NULL;//标记本段的K个节点。
if(p_pre==NULL){
reverse_range(p_start); //反转从start开始到NULL结束的一段
p_pre=p_start;
p_return=p_finish;
}
else
{
reverse_range(p_start);//反转从start开始到NULL结束的一段
p_pre->next=p_finish;
p_pre=p_start;
}
}
p_start=p_next_head;
p_finish=p_next_head;
}
return p_return;
}
};
我的代码(第2版)
在做了LeetCode (92) ReverseLinkedList2 这道题目之后,考虑利用这道题目的结果来进行改写本题的代码。如下:
//128ms过大集合
class Solution{
public: ListNode *reverseBetween(ListNode * & head, ListNode* & new_head, int m, int n) {
if (head == NULL)
return NULL;
ListNode *q = NULL; //q设定为NULL,p设定为head,这样的好处是,接下来可以用(q==NULL)来判断m是否为1,即head节点是否也参与了reverse,即第一段是否为空。
ListNode *p = head; //
for(int i = 0; i < m - 1; i++)
{
q = p;
p = p->next;
}
ListNode *end = p; //第二段反转后的尾节点。
ListNode *pPre = p;
p = p->next;
for(int i = m + 1; i <= n; i++)//从index=m走向index=n,走过n-m步,即i取值范围是[0,n-m),即[0,n-m-1],即[m+1,n]
{
ListNode *pNext = p->next;
p->next = pPre;
pPre = p;
p = pNext;
}
//最后一次循环,p和pNext都指向了第三段的第1个节点。此时不断p是否为空,都可以写为 "end->next = p; "这样就避免了对第三段是否为空的讨论。
end->next = p;
if (q) //如果第一段非空
{
q->next = pPre;
new_head=head;
}else{ //如果第一段为空
new_head = pPre;
}
return new_head;
}
ListNode *reverseKGroup(ListNode *head, int k) {
if(head==NULL||k==1)
return head;
ListNode* p=head;
ListNode* q=NULL;
ListNode* whole_head=NULL;
ListNode* whole_tail=NULL;
while(p!=NULL){
ListNode* k_start=p;
ListNode* k_end=NULL;
int count=0;
for(count=0;(p!=NULL&&count<k);count++){
//p取值范围从m到n+1,q取值范围从m到n,即p指向超出末端的下一位。保留下一次反转的起始节点
q=p;
p=p->next;
}
if(count!=k){ //不足K个
if(whole_head==NULL){
whole_head=k_start;
whole_tail=k_end;
}else{
whole_tail->next=k_start;
whole_tail=k_end;
}
}else{ //足够K个
reverseBetween(k_start,k_end,1,k);
if(whole_head==NULL){
whole_head=k_end;
whole_tail=k_start;
}else{
whole_tail->next=k_end;
whole_tail=k_start;
}
}
}
return whole_head;
}
}
我的代码(第3版) 因为使用递归一般都会使得代码更加简洁,所以本题也可试试使用递归来解决,果然代码一下子短多了。
//108ms过大集合
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode * reverseKGroup(ListNode *head, int k) {
ListNode* whole_head=NULL;
ListNode* pre=NULL;
ListNode* cur=head;
int count=0;
while(count<k&&cur!=NULL){
pre=cur;
cur=cur->next;
count++;
}
if(count==k){
ListNode* p=head;
ListNode* q=head->next;
ListNode* r=NULL;
while(q!=cur){
r=q->next;
q->next=p;
p=q;
q=r;
}
whole_head=p;
head->next=reverseKGroup(cur,k);
}else{
whole_head=head;
}
return whole_head;
}
};
update: 2015-01-03 和上面的第三版(递归版)基本一样
// 132ms
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *reverseKGroup(ListNode *head, int k) {
if(k == 0 || k==1 || head == NULL)
return head;
ListNode* current = head;
int count = k;
while (count > 0) {
if (current == NULL)
break;
current = current->next;
--count;
}
if (count > 0)
return head;
ListNode* previous = head;
ListNode* next = head->next;
current = head;
count = k;
while (count > 1) {
previous = current;
current = next;
if(next != NULL)
next = next->next;
current->next = previous;
--count;
}
head->next = NULL;
count = k;
head->next = reverseKGroup(next, count);
return current;
}
};