LeetCode #25 Reverse Nodes in k-Group
题目描述
给出一个单向链表,再给出一个常数k。
任务如下:
步骤一:讲单向链表前k个元素的顺序倒转
步骤二:剩下的元素重复执行步骤一、步骤二,直到剩下的元素不足k个。
要求:只允许使用常量级别的额外空间。
例子:
原链表:1->2->3->4->5
当k=2:2->1->4->3->5
当k=3:3->2->1->4->5
算法思路
我的算法是使用递归实现的。
首先,我们需要一个临时链表元素tmp,用于将两个链表元素反向。代码实现如下:
tmp=now->next;
now->next=tmp->next;
tmp->next=now;
图示化如下:
可以注意到,这个过程是需要通过回溯才能完成的,也就是我一开头所说的递归了。
但是这样还不够,这样只能将k个翻转了,那这两个k-group之间要怎么连接呢?这就需要用到另一个额外变量链表元素tmpk
在链表往下链的过程中,我们需要一个计数器count,记录当前到了第几个链表元素。在回溯的过程中,count%k ==0,则说明这是一组k-group的最后一个元素,对这个元素的处理如下代码:
if (tot%k==0) //这里tot即count计数器
{
now->next=tmpk;
tmpk=now;
}
图示化如下:
完成这两步,基本就完成全部了,剩下的就是判断一下最后面不足k个的不需要翻转。
额外空间需求:2个ListNode变量:tmp tmpk,1个int变量 count,1个bool变量(用于判断最后不足k个)
时间复杂度:O(n)
存在的问题:我这个算法完全建立在递归回溯的基础上,如果链表元素过多,会导致栈空间不足。
我也思考了一下不用递归的做法,虽然还没想到怎么写,但时间复杂度应该是会变成O(kn),k为常量,而空间上应该也会用到更多的额外空间。最后从代码复杂度来说,应该也是更高的。
代码
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
if (head==NULL) return head;
bb=false;
tot=0;
tmpk=head;
dfs(head,k);
return tmpk;
}
private:
bool bb;
int tot;
ListNode* tmpk;
void dfs(ListNode*now,int k)
{
ListNode *tmp;
tot++;
if (now->next!=NULL) dfs(now->next,k);
if (bb==false && tot%k==0)
{
bb=true;
tmpk=now;
}
else if (tot%k==0)
{
now->next=tmpk;
tmpk=now;
}
else if (bb && tot%k!=0)
{
tmp=now->next;
now->next=tmp->next;
tmp->next=now;
}
tot--;
return;
}
};