【LeetCode-链表】旋转链表
题目描述
给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。
示例:
输入: 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
输入: 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
题目链接: https://leetcode-cn.com/problems/rotate-list/
思路1
经过分析可以知道:把链表向右旋转 k 个位置,就是把链表从位置 len-(k%len) 处分成两段,将后一段指向前一段即可,其中 len 是链表长度。代码如下:
/**
* 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) {
if(head==nullptr) return nullptr;
int len = getLength(head);
int breakPoint = len - (k%len); // 链表断裂的位置
if(breakPoint==len) return head; // 相当于不旋转,直接返回
ListNode* node = head;
for(int i=0; i<breakPoint-1; i++){ // 注意是 i<breakPoint-1
node = node->next;
}
ListNode* newHead = node->next; // newHead是后一段链表的链表头
node->next=nullptr;
ListNode* temp = newHead;
while(temp->next!=nullptr){
temp = temp->next;
}
temp->next = head; // 将后一段链表的链表尾指向前一段链表的链表头
return newHead;
}
/*计算链表长度*/
int getLength(ListNode* head){
int len = 0;
while(head!=nullptr){
len++;
head = head->next;
}
return len;
}
};
这样写也行:
/**
* 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) {
if(head==NULL || k==0 || head->next==NULL) return head;
int len = getLen(head);
k = k % len;
if(k==0) return head;
ListNode* slow = head;
ListNode* fast = head;
for(int i=0; i<k; i++){
fast = fast->next;
}
while(fast->next!=NULL){
slow = slow->next;
fast = fast->next;
}
ListNode* head2 = slow->next;
slow->next = NULL;
fast->next = head;
return head2;
}
int getLen(ListNode* head){
int len = 0;
while(head!=NULL){
head = head->next;
len++;
}
return len;
}
};
这样写是找倒数第 k 个节点。
- 时间复杂度:O(n)
- 空间复杂度:O(1)
思路2
首先将链表首位相连变成环,然后从breakPoint处断开。代码如下:
/**
* 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) {
if(head==nullptr || head->next==nullptr) return head;
ListNode* tail = head;
int len = 1;
while(tail->next!=nullptr){
tail = tail->next;
len++;
}
tail->next = head; // 将链表首尾相连变成环
ListNode* newTail = head;
for(int i=0; i<len-k%len-1; i++){ // 获取断裂的位置,注意是 breakPoint-1
newTail = newTail->next;
}
ListNode* newHead = newTail->next;
newTail->next = nullptr;
return newHead;
}
};
其实思路 2 本质上和思路 1 是一样的。
- 时间复杂度:O(n)
- 空间复杂度:O(1)