描述
给定链表的头节点,旋转链表,降链表每个节点往右移动 k 个位置,原链表后 k 个位置的节点则依次移动到链表头。
即,例如链表 : 1->2->3->4->5 k=2 则返回链表 4->5->1->2->3
数据范围:链表中节点数满足
,
问题分析:循环移位,其实跟数租循环移位差不多,只不过数组可以直接获得数租长度,而链表长度未知。所以需要先
遍历一遍链表获得链表长度num,不能先操作,因为k可能比链表长度大。然后用k对num取余,结果肯定比链表长度小。
然后让两个指针同时指向head,先让一个指针走k步(也可以一步一步走k步),这里还是采用每次走两步,走k/2步,
只不过需要判断k是奇数还是偶数。是奇数时,走完k/2步后再向后走一步,然后两个指针同步走,直到快指针的下一个指向
nullptr(注意快指针不能走到nullptr),因为对链表的操作是需要让快指针指向头节点的,然后让头节点指向慢指针的
下一个作为新表头。最后还需要让慢指针的下一个指向nullptr,不然就是一个循环链表。
具体过程看下面代码,有详细注释。
复杂度分析:
时间复杂度O(n):先找链表尾部O(n/2),第二次遍历O(n)。
空间复杂度O(1):只定义了两个指针变量和一个int变量。
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) : val(x), next(nullptr) {}
* };
*/
class Solution {
public:
ListNode* rotateLinkedList(ListNode* head, int k) {
// write code here
if(head==nullptr||head->next==nullptr||0==k) return head;
ListNode *tmp=head,*tmp2;
int num=0;
//利用指针每次走两步,快速定位到结尾
while(tmp->next!=nullptr&&tmp!=nullptr) tmp=tmp->next->next,++num;
if(tmp==nullptr) num=2*num;
else num=2*num+1;
k%=num;//k可能大于num,所以需要先取余
if(k==0) return head;//k%num==0,说明移动链表总长度的倍数相当于没移动
tmp=head,tmp2=head;
if(!(k&1)) {//k是偶数,直接让tem每次走两步,走k/2步就到了第k个了。
k/=2;
while(k>0) tmp=tmp->next->next,--k;
}
else {//k是奇数,tmp每次走两步,走k/2步后再走一步就到第k个了
k/=2;
while(k>0) tmp=tmp->next->next,--k;
tmp=tmp->next;
}
//然后每次两个都只走一步,直到前面的到达null,然后直接修改指针指向
while(tmp->next!=nullptr) tmp=tmp->next,tmp2=tmp2->next;
tmp->next=head;//将尾节点指向头节点
head=tmp2->next;//将头指针指向慢走的下一个作为新表头
tmp2->next=nullptr;//将慢指针的下一个指向nullptr
return head;
}
};

京公网安备 11010502036488号