【面试经典150 | 链表】旋转链表

文章目录

Tag

【单向链表】


题目来源

61. 旋转链表


题目解读

旋转链表,将链表的每个节点向右移动 k 个位置。


解题思路

方法一:遍历

本题题目意思清晰,实现起来比较容易,属于链表基础知识题。

简单题我们仔细做,通过这道简答题来回顾一下单向链表的一些基本操作。

在进行具体的旋转链表操作之前,我们要先统计一下链表的长度 n,为什么?因为要 "将链表的每个节点向右移动 k 个位置",如果 k >= n,我们只需要将链表的每个节点向右移动 k % n 个位置即更新 k %= mk / n 表示要将链表的每个节点向右移动整数个 n 位置,把长度为 n 的链表向右移动 n 个位置等于没有动。

如何求链表的长度 n ?通过迭代枚举单向链表中的所有节点,计数得到链表的长度。具体地,初始化 n = 0,从头结点出发枚举节点,枚举到一个节点 ++n,接着更新当前节点为下一个节点,直到遇到空节点表示链表迭代枚举结束,退出。

将链表的每个节点向右移动 k 个位置,那么原链表的倒数第 k 个节点就是移动后链表的最后一个非空节点,也就是空节点的前一个节点,我们需要找到该节点,然后连上空节点。并且还要将原链表的最后一个非空节点连接到原链表的头结点,这才算完成移动操作(也就是题目说的选择链表)。

在代码实现中,我们先实现的是连接头节点(也就是 官方题解 中说的闭合成环),于是需要遍历原链表找到最后一个非空节点,这个我们可以在计算链表长度的时候将原链表的最后一个非空节点记录下来。然后将移动后链表的最后一个非空节点连接到空节点上,通过从 head 节点往后迭代 n - k - 1 次即可得到移动后链表的最后一个非空节点 lastNode,而 lastNode->next 节点就是我们最终要返回的向右移动后的新链表的头节点。

实现代码

cpp 复制代码
/**
 * Definition for singly-linked list.
 * 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) {}
 * };
 */
class Solution {
public:

    ListNode* rotateRight(ListNode* head, int k) {
        if(head == nullptr || head->next == nullptr) {
            return head;
        }

        // 计算链表长度
        ListNode* curr = head;
        int n = 1;
        while(curr->next != nullptr) {
            ++n;
            curr = curr->next;
        }

        k %= n;
        if(k == 0) {
            return head;
        }

        // 连接头结点
        curr->next = head;  // 注意此行代码放置的位置

        // 找出移动后链表的最后一个非空节点
        n -= k;
        lastNode = head;
        while(--n) {
            lastNode = lastNode->next;
        }

        // 建立新的头结点
        ListNode* newHead = lastNode->next;
        lastNode->next = nullptr;
        return newHead;
    }
};

复杂度分析

时间复杂度: O ( n ) O(n) O(n), n n n 是链表的长度,最坏情况下,我们需要遍历该链表两次。

空间复杂度: O ( 1 ) O(1) O(1),我们只需要常数的空间存储若干变量。


其他语言

python3

py3 复制代码
class Solution:
    def rotateRight(self, head: ListNode, k: int) -> ListNode:
        if not head or not head.next:
            return head
        
        n = 1
        cur = head
        while cur.next:
            cur = cur.next
            n += 1
        
        k %= n
        if k == 0:
            return head;
        
        cur.next = head
        
        cur = head
        n -= k
        n -= 1
        while n:
            cur = cur.next
            n -= 1
        
        newHead = cur.next
        cur.next = None
        return newHead

写在最后

如果文章内容有任何错误或者您对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。

如果大家有更优的时间、空间复杂度方法,欢迎评论区交流。

最后,感谢您的阅读,如果感到有所收获的话可以给博主点一个 👍 哦。

相关推荐
Dovis(誓平步青云)1 小时前
基于探索C++特殊容器类型:容器适配器+底层实现原理
开发语言·c++·queue·适配器·stack
Gyoku Mint1 小时前
深度学习×第4卷:Pytorch实战——她第一次用张量去拟合你的轨迹
人工智能·pytorch·python·深度学习·神经网络·算法·聚类
葫三生2 小时前
如何评价《论三生原理》在科技界的地位?
人工智能·算法·机器学习·数学建模·量子计算
pipip.3 小时前
UDP————套接字socket
linux·网络·c++·网络协议·udp
拓端研究室5 小时前
视频讲解:门槛效应模型Threshold Effect分析数字金融指数与消费结构数据
前端·算法
随缘而动,随遇而安7 小时前
第八十八篇 大数据中的递归算法:从俄罗斯套娃到分布式计算的奇妙之旅
大数据·数据结构·算法
孞㐑¥7 小时前
Linux之Socket 编程 UDP
linux·服务器·c++·经验分享·笔记·网络协议·udp
IT古董7 小时前
【第二章:机器学习与神经网络概述】03.类算法理论与实践-(3)决策树分类器
神经网络·算法·机器学习
水木兰亭10 小时前
数据结构之——树及树的存储
数据结构·c++·学习·算法
Jess0711 小时前
插入排序的简单介绍
数据结构·算法·排序算法