0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

移动旋转链表的每个节点

算法与数据结构 来源:吴师兄学算法 作者:吴师兄 2022-10-25 18:05 次阅读

一、题目描述

给你一个链表的头节点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]
231674e4-4859-11ed-a3b6-dac502259ad0.png

提示:

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

-100 <= Node.val <= 100

0 <= k <= 2 * 10^9

原题地址:https://leetcode.cn/problems/rotate-list/

二、题目解析

1、首先遍历整个链表,求出链表的长度len。

2、根据题目的提示,k可能很大,远超链表的长度,这样就会导致一种情况,比如 k = 1000,len = 999,每个节点向右移动 1 个节点和向右移动 k = 1000 个节点结果一样,所以进行一个取模的操作可以节省大量的移动操作。

3、接下来设置两个指针 former、latter 均指向链表的头节点,这两个指针的目的是去寻找出旋转之前的尾节点位置、旋转成功之后的尾节点位置

4、先让former指针先向前移动 k 次,此时,former就和latter相距 k 个节点了。

5、接下来,让former、latter同时向后移动,直到former来到了最后一个节点位置。

23256972-4859-11ed-a3b6-dac502259ad0.png

6、这个时候,从head到latter有len - k个节点,latter + 1 到 former 有 k 个节点。

7、也就意味着,latter + 1这个节点是移动 k 个节点成功之后的头节点。

2330f4c2-4859-11ed-a3b6-dac502259ad0.png

8、只需要返回latter + 1后面这个节点newHead,并且断开连接就行了。

三、参考代码

1、Java 代码

//登录AlgoMooc官网获取更多算法图解
//https://www.algomooc.com
//作者:程序员吴师兄
//代码有看不懂的地方一定要私聊咨询吴师兄呀
//旋转链表(LeetCode61)//leetcode.cn/problems/rotate-list/
classSolution{
publicListNoderotateRight(ListNodehead,intk){

//边界条件判断
if(head==null){
returnhead;
}

//1、第一步先要计算出链表的长度来
intlen=0;

//2、这里我们设置一个指针指向链表的头节点的位置
ListNodetempHead=head;

//3、通过不断的移动tempHead,来获取链表的长度
while(tempHead!=null){

//tempHead不断向后移动,直到为null
tempHead=tempHead.next;

//每次遍历一个新的节点,意味着链表长度新增1
len++;

}

//由于题目中的k会超过链表的长度,因此进行一个取余的操作
//比如k=1000,len=999
//实际上就是将链表每个节点向右移动1000%999=1个位置就行了
//因为链表中的每个节点移动len次会回到原位
k=k%len;


//4、接下来设置两个指针指向链表的头节点
//这两个指针的目的是去寻找出旋转之前的尾节点位置、旋转成功之后的尾节点位置

//former指针
ListNodeformer=head;

//latter指针
ListNodelatter=head;

//former指针先向前移动k次
for(inti=0;i< k ; i++){

            // former 不断向后移动
            former = former.next;

        }

        // 这样 former 和 latter 就相差了 k 个节点
        // 5、接下来,两个指针同时向后移动,直到 former 来到了最后一个节点位置
        while(former.next != null){

            // former 不断向后移动
            former = former.next;

            // latter 不断向后移动
            latter = latter.next; 
        }

        // 6、此时,former 指向了最后一个节点,需要将这个节点和原链表的头节点连接起来
        former.next = head;

        // 7、latter 指向的节点的【下一个节点】是倒数第 k 个节点,那就是旋转成功之后的头节点
        ListNode newHead = latter.next;

        // 8、断开链接,避免成环
        latter.next = null;

        // 9、返回 newHead
        return newHead;

    }
}

2、C++ 代码

classSolution{
public:
ListNode*rotateRight(ListNode*head,intk){

//边界条件判断
if(head==NULL){
returnhead;
}

//1、第一步先要计算出链表的长度来
intlen=0;

//2、这里我们设置一个指针指向链表的头节点的位置
ListNode*tempHead=head;

//3、通过不断的移动tempHead,来获取链表的长度
while(tempHead!=NULL){

//tempHead不断向后移动,直到为NULL
tempHead=tempHead->next;

//每次遍历一个新的节点,意味着链表长度新增1
len++;

}

//由于题目中的k会超过链表的长度,因此进行一个取余的操作
//比如k=1000,len=999
//实际上就是将链表每个节点向右移动1000%999=1个位置就行了
//因为链表中的每个节点移动len次会回到原位
k=k%len;


//4、接下来设置两个指针指向链表的头节点
//这两个指针的目的是去寻找出旋转之前的尾节点位置、旋转成功之后的尾节点位置

//former指针
ListNode*former=head;

//latter指针
ListNode*latter=head;

//former指针先向前移动k次
for(inti=0;i< k ; i++){

            // former 不断向后移动
            former = former->next;

}

//这样former和latter就相差了k个节点
//5、接下来,两个指针同时向后移动,直到former来到了最后一个节点位置
while(former->next!=NULL){

//former不断向后移动
former=former->next;

//latter不断向后移动
latter=latter->next;
}

//6、此时,former指向了最后一个节点,需要将这个节点和原链表的头节点连接起来
former->next=head;

//7、latter指向的节点的【下一个节点】是倒数第k个节点,那就是旋转成功之后的头节点
ListNode*newHead=latter->next;

//8、断开链接,避免成环
latter->next=NULL;

//9、返回newHead
returnnewHead;

}
};

3、Python 代码

classSolution:
defrotateRight(self,head:Optional[ListNode],k:int)->Optional[ListNode]:
#边界条件判断
ifnotheadork==0:
returnhead

#1、第一步先要计算出链表的长度来
_len=0

#2、这里我们设置一个指针指向链表的头节点的位置
tempHead=head

#3、通过不断的移动tempHead,来获取链表的长度
whiletempHead:

#tempHead不断向后移动,直到为NULL
tempHead=tempHead.next

#每次遍历一个新的节点,意味着链表长度新增1
_len+=1



#由于题目中的k会超过链表的长度,因此进行一个取余的操作
#比如k=1000,len=999
#实际上就是将链表每个节点向右移动1000%999=1个位置就行了
#因为链表中的每个节点移动len次会回到原位
k=k%_len


#4、接下来设置两个指针指向链表的头节点
#这两个指针的目的是去寻找出旋转之前的尾节点位置、旋转成功之后的尾节点位置

#former指针
former=head

#latter指针
latter=head

#former指针先向前移动k次
foriinrange(0,k):

#former不断向后移动
former=former.next


#这样former和latter就相差了k个节点
#5、接下来,两个指针同时向后移动,直到former来到了最后一个节点位置
whileformer.next:

#former不断向后移动
former=former.next

#latter不断向后移动
latter=latter.next


#6、此时,former指向了最后一个节点,需要将这个节点和原链表的头节点连接起来
former.next=head

#7、latter指向的节点的【下一个节点】是倒数第k个节点,那就是旋转成功之后的头节点
newHead=latter.next

#8、断开链接,避免成环
latter.next=None

#9、返回newHead
returnnewHead

四、复杂度分析

时间复杂度:链表一共被遍历两次,因此总的时间复杂度为O(n),n是链表的长度。

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





审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • JAVA
    +关注

    关注

    19

    文章

    2904

    浏览量

    102994

原文标题:旋转链表(LeetCode 61)

文章出处:【微信号:TheAlgorithm,微信公众号:算法与数据结构】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    C语言-链表(单向链表、双向链表)

    在前面章节已经学习了数组的使用,数组的空间是连续空间,数组的大小恒定的,在很多动态数据存储的应用场景下,使用不方便;而这篇文章介绍的链表结构,支持动态增加节点,释放节点,比较适合存储动态数据的应用场景,而且
    的头像 发表于 09-09 11:30 1386次阅读

    C语言实现单链表-增删改查

    链表是由一连串节点组成的数据结构,每个节点包含一个数据值和一个指向下一个节点的指针。链表可以在头
    的头像 发表于 05-25 15:05 940次阅读
    C语言实现单<b class='flag-5'>链表</b>-增删改查

    C语言单向链表

    本帖最后由 snowmay001 于 2016-5-22 15:57 编辑 lianbiao.cpp/* 练习使用链表:创建链表、遍历链表、查找节点、添加
    发表于 05-22 15:53

    Linux内核的链表操作

    ) 搬移Linux提供了将原本属于一个链表节点移动到另一个链表的操作,并根据插入到新链表的位置分为两类:static inline voi
    发表于 08-29 11:13

    玩转C语言链表-链表各类操作详解

    p节点之后,已经改变了first节点,所以first节点应该在被修改之前往后移动,不能放到下面注释的位置上去  first = first->next; //无序
    发表于 09-18 13:30

    数据结构链表的基本操作

    嵌入式学习基础-数据结构链表的基本操作链表节点采用结构体的方式进行定义,下面是最基础的定义只有一个数据data,*pNext用于指向下一个节点(若为尾
    发表于 12-22 08:05

    RT-Thread内核中单链表的使用与实现

    )组成,每个节点都有指向下一个节点的指针。节点的连接方向是单向的,节点之间用指针连起来,所有结构体类型可以不一样,
    发表于 04-01 12:01

    RT-Thread内核中双链表的使用与实现

    1. 单链表与双链表链表: 由一个个节点(node)组成,每个节点都有指向下一个
    发表于 04-01 12:05

    OpenHarmony中的HDF单链表及其迭代器

    , or NULL};如上图所述,每个节点都是HdfSListNode,上图共有5个节点每个节点内部有一个next成员,其值为下
    发表于 08-30 10:31

    OpenHarmony中的HDF单链表及其迭代器

    , or NULL};如上图所述,每个节点都是HdfSListNode,上图共有5个节点每个节点内部有一个next成员,其值为下
    发表于 09-05 11:38

    C语言基础教程之链表

    (一)什么是链表链表是一种常见的基础数据结构,是一种线性表,是一种在物理存储单元上非连续非顺序的存储结构。 链表有一系列节点构成,节点
    发表于 11-16 10:22 2059次阅读

    合并两个排序的链表

    的头结点; 2、依次比较两个链表节点的大小,将一个链表合并到另一个链表中; 3、合并完之后,剩余部分合并到新链表最后; 我的代码 /*str
    发表于 01-16 22:02 477次阅读

    驱动之路-内核链表的使用

    kernel list展示的是内核链表的结构,normallist展示的是普通链表的结构。head是链表头,p1,p2,p3是链表节点。从图
    发表于 05-15 17:24 1184次阅读
    驱动之路-内核<b class='flag-5'>链表</b>的使用

    链表学习的超详细说明(二)

    昨天跟大家分享了单链表的一些基本用法,今天接着继续和大家分享单链表的用法,今天分享完,单链表的操作就暂告一段落了,后面接着分享双链表的学习和实战!一、单
    的头像 发表于 12-24 17:33 618次阅读

    链表和双链表的区别在哪里

    链表和双链表的区别 单链表的每一个节点中只有指向下一个结点的指针,不能进行回溯。 双链表的每一个节点
    的头像 发表于 07-27 11:20 1105次阅读
    单<b class='flag-5'>链表</b>和双<b class='flag-5'>链表</b>的区别在哪里