LeetCode 61旋转链表
-
题目简述:给定一个链表,旋转链表,将链表每个节点向右移动
k
个位置,其中k
是非负数。 -
示例1:
输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL示例2:
输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
向右旋转 1 步: 2->0->1->NULL
向右旋转 2 步: 1->2->0->NULL
向右旋转 3 步: 0->1->2->NULL
向右旋转 4 步: 2->0->1->NULL -
思路一:
- 首先新建一个虚拟头节点
dummy
指向头结点 - 第一次遍历找到链表长度
n
以及尾结点tail
- 如果链表长度为0返回头节点,排除
n == 0
的情况,k
值可能会远大于n
,则令k = k%n
取得最终的移动位置,如果巧合k==0
则返回头节点 - 第二次遍历找到第
n - k
个节点地址cur
,然后令dummy
的下一个节点指向cur
的下一个节点;末尾节点的下一个节点指向原来的头节点;最后cur
的下一个节点指向空,跳出遍历循环返回dummy->next
- 时间复杂度分析:链表一共遍历2遍,所以总时间复杂度是 O(n)。
- 首先新建一个虚拟头节点
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* rotateRight(ListNode* head, int k) {
auto dummy = new ListNode(-1);
dummy -> next = head;
int n = 0;
auto cur = dummy;
while(cur -> next)
{
cur = cur -> next;
n ++;
}
auto tail = cur;
if(!n) return head;
k %= n;
if(!k) return head;
int i = 0;
cur = head;
while(cur)
{
i++;
if(i == n - k)
{
dummy -> next = cur -> next;
tail -> next = head;
cur -> next = NULL;
break;
}
cur = cur -> next;
}
return dummy -> next;
}
};
- 思路二:
- 第一次遍历找到链表长度
n
,如果链表长度为0则返回头节点,同时排除了n == 0
的情况,k
值可能会远大于n
,则令k = k%n
取得最终的移动位置,如果巧合k==0
则返回头节点 - 第二次遍历建立双指针同时指向头节点,让快指针先走
k
步,然后快慢指针同时移动直到快指针为空,此时快指针指向链表结尾,令快指针的下一个节点指向头节点;头节点更新为慢指针的下一个节点;慢指针的下一个节点更新为空。
- 第一次遍历找到链表长度
class Solution {
public:
ListNode* rotateRight(ListNode* head, int k) {
int n = 0;
auto cur = head;
while(cur)
{
cur = cur -> next;
n++;
}
if(!n) return head;
k %= n;
if(!k) return head;
auto first = head;
while(k-- && first) first = first -> next;
auto second = head;
while(first -> next)
{
first = first -> next;
second = second -> next;
}
first -> next = head;
head = second -> next;
second -> next = NULL;
return head;
}
};