旋转链表(中等难度)

简介: 旋转链表(中等难度)

题目概述(简单难度)

给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置,k为非负数.

示例 1:

2.png


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

输出:[4,5,1,2,3]


示例 2:

2.png


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

输出:[2,0,1]


在此附上leetcode链接:

点击此处进入leetcode


思路与代码

思路展现

这道题目我的思路是用快慢指针,思路是这样的:定义两个快慢指针,一个为fast指针,一个为slow指针,fast指针先行走k步,然后slow指针和fast指针同时从当前位置开始向后遍历,当fast指针所指向的节点的next域为null时,此时停止遍历,slow指针所指向的节点即为我们旋转后的链表的尾节点,slow指针所指向的节点的下一个节点即为我们旋转后的链表的头节点.

当然因为这道题目的特殊情况非常多,我也是在不断出错中完善的代码,所以我将代码中的特殊情况待会以代码的形式进行讲解,先来看完整的代码.


代码示例

class Solution {
    public ListNode rotateRight(ListNode head, int k) {
         if(head == null || k < 0){
             return null;
         }
         //特殊情况1:k=0的情况,就是原链表
         if(k==0){
             return head;
         }
         //特殊情况2:链表中只有一个节点的情况,不管k值多少,最后的链表还是其本身,就是原链表
         if(head.next==null){
             return head;
         }
         ListNode slow=head;
         ListNode fast=head;
         //fast指针先走k步
         while(k!=0){
             if(fast.next!=null){
                 fast=fast.next;
                 k--;
              //特殊情况3:当k的值大于链表节点的个数的时候,fast指针每次走到尾节点都需要返回到头节点继续遍历,直到走完k步
             }else{
                 fast=head;
                 k--;
             }
         }
         //fast指针走完k步后,此时slow指针和fast指针开始向后遍历,各走一步
         while(fast.next!=null){
             fast=fast.next;
             slow=slow.next;
         }
          //特殊情况4:假设k值与节点个数相同的情况,此时slow指针与fast指针必相遇,且一定相遇在原链表最后一个节点
         if(slow==fast){
             return head;
         }
         ListNode tmp=slow.next;
         slow.next=null;
         fast.next=head;
         head=tmp;
         return head;
    }
}

特殊情况

特殊情况1

首先当链表为null或者k小于0的时候,直接返回null即可.


特殊情况2

假设链表中此时只有一个节点,说明此时不管k的值为多少,再怎么旋转,都是原链表,所以判断head.next是否为空,如果为空,返回head指针所指向的头节点即可.


特殊情况3

在fast指针先走k步的时候也是存在特殊情况的:

当k的值大于链表长度的时候,此时的fast指针遍历到尾节点时需要重新指回头节点,直到走完k步.


特殊情况4

当fast指针走完k步后,此时slow指针和fast指针同时会从当前位置开始向后遍历.直到fast.next=null的时候停止遍历.

此时会出现一个特殊情况,当k的值与链表的节点个数相同的时候,此时slow指针和fast指针经过遍历后一定会相遇,且一定相遇在原链表的最后一个节点处,同学们下来可以拿链表【1,2】,k=2来做下实验,既然这样,此时返回head指针所指向的头节点即可,因为slow指针指向的节点代表旋转后的链表的尾节点,而这个尾节点正是原链表的尾节点,很显然新的旋转链表的头节点就是原链表的头节点了,并没有发生变化.


核心代码

核心的代码就是以下四句:


         ListNode tmp=slow.next;
         slow.next=null;
         fast.next=head;
         head=tmp;

核心代码的应用场景就是链表中节点的个数,也就是链表长度与k值不相等的情况

当不相等时,此时需要定义一个tmp变量来存储我们slow指针遍历完成后所指向的节点的下一个节点,原因是slow指针所指向的节点作为旋转后的链表的尾节点时,其next域必须置为空,所以此时会失去当前slow指针所指向的节点的下一个节点,而这个节点是要作为新的旋转过后的链表的头节点的,所以需要提前保存这个节点

因为不管fast指针如何遍历,最终fast指针都会指向原链表的尾节点,而我们要做的就是将这个尾节点与原链表的头节点进行相连,这样才能将链表串起来形成旋转过后的链表.

最后将新的链表的头节点也就是tmp赋给我们的头指针head,返回head即可.


总结

1:此算法:

时间复杂度:O(N)

空间复杂度:O(1)

2:此道题目仍然运用了我们的经典思路快慢指针法,他的做法与之前剑指offer中寻找链表倒数第k个节点的做法类似,在此我附上链接,同学们下来可自行复习下寻找链表倒数第k个节点这道题目.

相关文章
|
3月前
【bug记录】旋转链表与力扣报错:member access within null pointer of type ‘struct ListNode‘
【bug记录】旋转链表与力扣报错:member access within null pointer of type ‘struct ListNode‘
|
6月前
|
测试技术
ONT60 旋转链表 思路分享
先将整个链表整体反转,再分别反转前k个和剩下的。
32 0
|
6月前
|
存储 算法
LeetCode刷题--- 61. 旋转链表(快慢指针+闭合为环)
LeetCode刷题--- 61. 旋转链表(快慢指针+闭合为环)
|
6月前
|
Shell Linux 算法
Shell编程——弱数据类型的脚本语言快速入门指南
Shell编程——弱数据类型的脚本语言快速入门指南
93 0
Shell编程——弱数据类型的脚本语言快速入门指南
|
6月前
|
算法 C++ Python
Java每日一练(20230430) 文本左右对齐、素数和、整数转英文表示
Java每日一练(20230430) 文本左右对齐、素数和、整数转英文表示
54 0
Java每日一练(20230430) 文本左右对齐、素数和、整数转英文表示
|
6月前
|
Python Java Go
Python每日一练(20230430) 移除元素、删除排序链表中的重复元素、搜索旋转排序数组II
Python每日一练(20230430) 移除元素、删除排序链表中的重复元素、搜索旋转排序数组II
72 0
Python每日一练(20230430) 移除元素、删除排序链表中的重复元素、搜索旋转排序数组II
|
6月前
|
Python Go Java
Golang每日一练(leetDay0042) 二叉树最大路径和、回文串、单词接龙II
Golang每日一练(leetDay0042) 二叉树最大路径和、回文串、单词接龙II
56 0
Golang每日一练(leetDay0042) 二叉树最大路径和、回文串、单词接龙II
|
6月前
|
Python Go 机器人
Golang每日一练(leetDay0021) 旋转链表、不同路径、不同路径II
Golang每日一练(leetDay0021) 旋转链表、不同路径、不同路径II
56 0
Golang每日一练(leetDay0021) 旋转链表、不同路径、不同路径II
|
6月前
leetcode-61:旋转链表
leetcode-61:旋转链表
34 0
|
6月前
「LeetCode」61. 旋转链表
「LeetCode」61. 旋转链表
42 0