描述
给定链表的头节点,旋转链表,降链表每个节点往右移动 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; } };