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)原题链接

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

相关推荐
Thera7773 小时前
状态机(State Machine)详解:原理、优缺点与 C++ 实战示例
开发语言·c++
linux开发之路3 小时前
C++高性能日志库开发实践
c++·c++项目·后端开发·c++新特性·c++校招
刻BITTER3 小时前
在TRAE 上安装PlatformIO
c++·单片机·嵌入式硬件·arduino
永远都不秃头的程序员(互关)3 小时前
C++动态数组实战:从手写到vector优化
c++·算法
水力魔方4 小时前
武理排水管网模拟分析系统应用专题5:模型克隆与并行计算
数据库·c++·算法·swmm
OliverH-yishuihan5 小时前
在win10上借助WSL用VS2019开发跨平台项目实例
linux·c++·windows
汉克老师6 小时前
GESP2025年12月认证C++二级真题与解析(编程题1 (环保能量球))
c++·gesp二级·gesp2级
郝学胜-神的一滴6 小时前
Linux进程与线程控制原语对比:双刃出鞘,各显锋芒
linux·服务器·开发语言·数据结构·c++·程序人生
青岛少儿编程-王老师6 小时前
CCF编程能力等级认证GESP—C++2级—20251227
java·开发语言·c++
javachen__6 小时前
341-十道经典程序设计题目
数据结构·c++·算法