zoukankan      html  css  js  c++  java
  • 61#旋转链表

    题目描述

    给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。

    示例 1:

    输入: 1->2->3->4->5->NULL, k = 2
    输出: 4->5->1->2->3->NULL
    解释:
    向右旋转 1 步: 5->1->2->3->4->NULL
    向右旋转 2 步: 4->5->1->2->3->NULL
    

    示例 2:

    输入: 0->1->2->NULL, k = 4
    输出: 2->0->1->NULL
    解释:
    向右旋转 1 步: 2->0->1->NULL
    向右旋转 2 步: 1->2->0->NULL
    向右旋转 3 步: 0->1->2->NULL
    向右旋转 4 步: 2->0->1->NULL
    

    分析

    之前做过一个题,是旋转数组,把数组按要求向右循环移位。在旋转数组中,用到了按索引反转数组的一个辅助方法,先把数组整体反转,再分为两部分分别反转,就可以得到结果了。这个方法在链表中就不太适用了,因为链表获取索引很不方便。但是可以借鉴一下大致的思路,依然是把链表分成两部分,把后面一截移到前面一截的前面,不就完成了所谓的循环右移吗?

    对此,有两种方法:

    • 双指针+哑节点
    • 单指针

    说是两种方法,但其实第二种方法是第一种方法的改进,本质上都是刚才所说的把链表分成两部分,把后面一截移到前面一截的前面。

    双指针+哑节点

    1. 新建一个哑节点放在原链表前面
    2. 新建两个指针first,second指向哑节点
    3. 先把first移动到最后一个节点,同时记录下链表的长度len
    4. 再把second移动到第len-k个元素的位置
    5. 执行旋转操作。具体分3个步骤:
      • first跟首结点相连(成环)
      • 哑节点指向新链表的头部second.next
      • 断开second和新链表头部的链接

    需要注意的是,k要经过k %= len处理,将旋转转换为单圈。

    源码

    /**
     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode(int x) { val = x; }
     * }
     */
    class Solution {
        public ListNode rotateRight(ListNode head, int k) {
            if (head == null || head.next == null || k == 0) 
                return head;
            ListNode result = new ListNode(0); // 建立哑节点
            result.next = head;
            
            ListNode first = result;
            ListNode second = result;
            int len = 0;
            while (first.next != null){  // first 移到尾节点
                first = first.next;
                len++;
            }
            k %= len; // 转换为单圈
            for (int i = 0; i < len - k; i++){
                second = second.next;
            }
            first.next = result.next; // 旋转操作
            result.next = second.next;
            second.next = null;
            
            return result.next;
        }
    }
    

    单指针

    单指针实际上是刚才双指针法的简化版,只需要一个辅助指针p。具体步骤如下:

    1. 新建一个指针p,指向链表头部head
    2. 移动p到链表尾部,并记录链表长度
    3. 形成环状(p.next = head
    4. p移动到分界点,即p后面有k个元素
    5. head移动到p.next
    6. 断开phead的链接

    跟双指针一样,k要经过k %= len处理,将旋转转换为单圈。

    源码

    /**
     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode(int x) { val = x; }
     * }
     */
    class Solution {
        public ListNode rotateRight(ListNode head, int k) {
            if (head == null || head.next == null || k == 0) 
                return head;
            ListNode p = head;
            int len = 1;
            while (p.next != null){
                p = p.next;
                len++;
            }
            k %= len;
            p.next = head; // 成环
            for (int i = 0; i < len - k; i++){
                p = p.next; // p 移动到分界点
            }
            head = p.next;
            p.next = null;
            
            return head;
        }
    }
    
  • 相关阅读:
    第四章 瞬时响应:网站的高性能架构(待续)
    第三章 大型网站核心架构要素(待续)
    Luogu P1140 相似基因 【dp】By cellur925
    矩阵快速幂/矩阵加速线性数列 By cellur925
    [POI2008]BLO-Blockade 【无向图tarjan/鸽点】By cellur925
    USACO Training3.3 A Game【区间Dp】 By cellur925
    Luogu P2858 [USACO06FEB]奶牛零食Treats for the Cows 【区间dp】By cellur925
    Luogu P2921 在农场万圣节 【tarjan in 有向图】 By cellur925
    浅谈扩展欧几里得[exgcd] By cellur925
    NOIp 2014 联合权值 By cellur925
  • 原文地址:https://www.cnblogs.com/yuzhenzero/p/9633485.html
Copyright © 2011-2022 走看看