移动旋转链表的每个节点

描述

一、题目描述

给你一个链表的头节点 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]
JAVA

 

提示:

链表中节点的数目在范围 [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 来到了最后一个节点位置。

JAVA

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

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

JAVA

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

三、参考代码

1、Java 代码

 

// 登录 AlgoMooc 官网获取更多算法图解
// https://www.algomooc.com
// 作者:程序员吴师兄
// 代码有看不懂的地方一定要私聊咨询吴师兄呀
// 旋转链表(LeetCode 61)//leetcode.cn/problems/rotate-list/
class Solution {
    public ListNode rotateRight(ListNode head, int k) {
        
        // 边界条件判断
        if( head == null)  {
            return head;
        }

        // 1、第一步先要计算出链表的长度来
        int len = 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(int i = 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++ 代码

 

class Solution {
public:
    ListNode* rotateRight(ListNode* head, int k) {

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

        // 1、第一步先要计算出链表的长度来
        int len = 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(int i = 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;

    }
};

 

3、Python 代码

 

 class Solution:
    def rotateRight(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
        # 边界条件判断
        if not head or k == 0 :
            return head

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

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

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

            # 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 次
        for i in range(0 , k ) :

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


        # 这样 former 和 latter 就相差了 k 个节点
        # 5、接下来,两个指针同时向后移动,直到 former 来到了最后一个节点位置
        while former.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
        return newHead

 

四、复杂度分析

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

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





审核编辑:刘清

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

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分