LeetCode 面试经典 150_链表_旋转链表(64_61_C++_中等)

LeetCode 面试经典 150_链表_旋转链表(64_61_C++_中等)

题目描述:

给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。

输入输出样例:

示例 1:

输入 :head = [1,2,3,4,5], k = 2
输出:[4,5,1,2,3]

示例 2:

输入 :head = [0,1,2], k = 4
输出:[2,0,1]

提示:

链表中节点的数目在范围 [0, 500] 内

-100 <= Node.val <= 100

0 <= k <= 2 * 109

题解:

解题思路:

思路一(模拟):

1、例:head = 1->2->3->4->5->nullptr , k = 2

  • 统计head中元素的个数,并标记尾结点。 ListLength=5,尾结点为 5->nullptr
  • 若k >= ListLength, k= k%ListLength。若 k==0直接返回原列表
  • 查找断开位置也就是 3->4 之间,4作为新链表头需要标记,需将3后一个结点指向nullptr最为新链表末尾。1->2->3->nullptr。4->5->nullptr
  • 将链表进行连接 4->5->1->2->3->nullptr

2、复杂度分析:

① 时间复杂度:O(n),其中n是链表的长度。遍历链表一次获取节点数以及尾节点。

② 空间复杂度:O(1),只使用了常数额外空间。

代码实现

代码实现(思路一(模拟)):
cpp 复制代码
class Solution {
public:
    // 函数:将链表向右旋转k次
    ListNode* rotateRight(ListNode* head, int k) {
        // 如果链表为空或链表中只有一个节点,或者k为0,则不需要旋转,直接返回原链表头节点
        if (head == nullptr || head->next == nullptr || k == 0) {
            return head;
        }
        
        int numNode = 0;  // 用来统计链表的节点数量
        ListNode* curNode = head;  // 当前节点指针,用来遍历链表
        ListNode* tailNode = nullptr;  // 记录链表的尾节点
        
        // 遍历链表,统计链表中的节点数量,并且找到尾节点
        while (curNode != nullptr) {
            numNode++;  // 节点数加一
            tailNode = curNode;  // 更新尾节点为当前节点
            curNode = curNode->next;  // 移动到下一个节点
        }
        
        // 如果k大于链表的长度,使用k % numNode来减少不必要的旋转
        k = k % numNode;  // 例如:旋转numNode次是等价的(即原链表不变)
        
        // 如果k为0,表示不需要旋转,直接返回原链表头节点
        if (k == 0) {
            return head;
        }
        
        curNode = head;  // 重置curNode为头节点,准备遍历链表找到新的尾节点
        int n = numNode - k - 1;  // 计算新的尾节点前一个节点的位置(即新链表的尾节点)
        
        // 遍历链表,找到新的尾节点,即旋转后链表的倒数第k个节点
        while (n) {
            curNode = curNode->next;  // 移动到下一个节点
            n--;  // 剩余步数减少
        }
        
        // 此时,curNode是新的尾节点,curNode->next将是新的头节点
        tailNode->next = head;  // 将原链表的尾节点连接到头节点,形成一个循环链表
        head = curNode->next;  // 将新的头节点设置为curNode的下一个节点
        curNode->next = nullptr;  // 将新的尾节点的next指针设为nullptr,断开循环,恢复链表结构
        
        return head;  // 返回新的头节点
    }
};
以思路一为例进行调试
cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;

struct ListNode
{
    int val;
    ListNode *next;
    ListNode():val(0),next(nullptr){}
    ListNode(int x):val(x),next(nullptr){}
    ListNode(int x,ListNode *next):val(x),next(next){}
};

//尾插法创建单链表
ListNode *createList(vector<int> &nums){
    ListNode *head=nullptr,*tail=nullptr;
    for (auto &num : nums){
        if (head==nullptr){
            head=tail=new ListNode(num);
        }else{
            tail->next=new ListNode(num);
            tail=tail->next;
        }
    }
    return head;
}

class Solution {
public:
    // 旋转链表,右旋k次
    ListNode* rotateRight(ListNode* head, int k) {
        // 如果链表为空、只有一个节点或者旋转次数为0,直接返回原链表
        if (!head || !head->next || k == 0) {
            return head;
        }
        
        // 统计链表中的节点个数
        ListNode *curNode = head;
        int ListLength = 1;  // 链表至少有一个节点,所以初始值为1

        ListNode *tailNode=nullptr;
        while(curNode!=nullptr){
            ListLength++;
            tailNode=curNode;
            curNode=curNode->next;
        }
        
        // 记录尾节点
        ListNode *tail = curNode;

        // 对k取余,避免旋转次数大于链表长度
        k %= ListLength;
        
        // 如果k是0,表示旋转后链表没有变化,直接返回原链表
        if (k == 0) {
            return head;
        }
        
        // 计算断开的位置,从头开始找到第ListLength-k个节点
        int n = ListLength - k;
        ListNode *preNode = nullptr;
        curNode = head;  
        
        // 寻找断开的位置,即第ListLength-k个节点
        while (n) {
            preNode = curNode;
            curNode = curNode->next;
            n--;
        }

        // 断开链表并重新连接
        preNode->next = nullptr;  // 将第ListLength-k个节点的前一个节点的next设为null,断开链表
        tail->next = head;  // 将尾节点指向头节点,形成一个环状链表

        return curNode;  // 新的头节点
    }
};

int main(int argc, char const *argv[])
{
    vector<int> nums={1,2,3,4,5};
    ListNode *head=createList(nums);
    int k=2;
    //测试单链表是否创建成功
    // while (head)
    // {
    //     cout<<head->val<<" ";
    //     head=head->next;
    //     /* code */
    // }
    Solution s;
    ListNode*ans= s.rotateRight(head,k);
    while (ans)
    {
        cout<<ans->val<<" ";
        ans=ans->next;
        /* code */
    }
    return 0;
}

LeetCode 面试经典 150_链表_旋转链表(64_61)原题链接

欢迎大家和我沟通交流(✿◠‿◠)

相关推荐
阿健君8 小时前
Android 高频八股文十问
面试
坚持编程的菜鸟8 小时前
LeetCode每日一题——Pow(x, n)
c语言·算法·leetcode
T___T9 小时前
AIGC 实战:用 pnpm 提速 + Node.js 调用 OpenAI 🤖
面试·node.js
CS创新实验室10 小时前
典型算法题解:长度最小的子数组
数据结构·c++·算法·考研408
我有一些感想……10 小时前
浅谈 BSGS(Baby-Step Giant-Step 大步小步)算法
c++·算法·数论·离散对数·bsgs
j_xxx404_10 小时前
C++ STL:string类(3)|operations|string类模拟实现|附源码
开发语言·c++
Wenhao.10 小时前
LeetCode LRU缓存
算法·leetcode·缓存·golang
小白菜又菜11 小时前
Leetcode 2273. Find Resultant Array After Removing Anagrams
算法·leetcode·职场和发展
Swift社区11 小时前
LeetCode 409 - 最长回文串 | Swift 实战题解
算法·leetcode·swift