【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)
posted @ 2020-05-11 17:05  Flix  阅读(161)  评论(0编辑  收藏  举报