61. 旋转链表

作者: 王可尊 | 来源:发表于2019-01-12 00:39 被阅读0次

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

一开始可以发现,有如下三种特殊情况是可以直接不进行任何处理,直接返回head的:

  • headnull,整个链表都是null
  • headnext为空,代表链表只有一个元素,此时不论右移多少次,都是本身
  • k=0

考虑k的取值, 如果k的值正好是链表长度的整数倍,这种情况右移后还是原链表本身。返回即可。
接下来,如果k远远超过链表的长度,我们也没必要进行过多的右移,获取k对链表长度的余数即为右移的次数。
一个难点在于,在单向链表中找到一个元素的父亲节点的时间复杂度很高。此时第一个想法是翻转链表、新链表左移、再次翻转链表。
也写出了第一版代码。

代码1

java实现

class Solution {
    public ListNode rotateRight(ListNode head, int k) {
        //三种情况,链表为空、链表只有一个元素、移动位置为0
        if (head == null ||head.next == null || k == 0) {
            return head;
        }
        ListNode tail = head;
        ListNode temp = head;
        //判断长度
        int i = 1;
        while (temp.next != null) {
            temp = temp.next;
            i++;
        }
        
        k = k % i;
        //当旋转整数倍时,没有必要挪动数据,直接返回head
        if (k == 0) {
            return head;
        }
        
        //翻转链表
        head = reverse(head);
        while(k>0) {
            tail.next = head;
            tail = head;
            head = head.next;
            tail.next = null;
            k--;
        }
        head = reverse(head);
        return head;
        
    }
    
    //翻转链表
    ListNode reverse (ListNode head) {
        ListNode prev = head;
        ListNode curr = head.next;
        while (curr!=null) {
            ListNode temp = curr.next;
            curr.next = prev;
            prev = curr;
            curr = temp;
        }
        head.next = null;
        return prev;
    }
}

解法2

解法1的问题在于有两次翻转链表,虽然只是O(n)的时间复杂度,但是本着能少一步是一步的原则,还是能省则省。
继续观察示例1,发现,右移2位,实际上是左移3位,而左移是解法1里就实现了的。这就不需要翻转链表就可以直接移动了。

代码2

java实现

class Solution {
    public ListNode rotateRight(ListNode head, int k) {
        //三种情况,链表为空、链表只有一个元素、移动位置为0
        if (head == null ||head.next == null || k == 0) {
            return head;
        }
        ListNode tail = head;
        ListNode temp = head;
        //判断长度
        int i = 1;
        while (tail.next != null) {
            temp = tail;
            tail = tail.next;
            i++;
        }
        
        k = k % i;
        //当旋转整数倍时,没有必要挪动数据,直接返回head
        if (k == 0) {
            return head;
        }
        //增加了一步k的计算
        k = i-k;
        
        //翻转链表
        //注释掉解法1的翻转链表
        //head = reverse(head);
        while(k>0) {
            tail.next = head;
            tail = head;
            head = head.next;
            tail.next = null;
            k--;
        }
        //注释掉解法1的翻转链表
        //head = reverse(head);
        return head;
        
    }
    
    //翻转链表
    ListNode reverse (ListNode head) {
        ListNode prev = head;
        ListNode curr = head.next;
        while (curr!=null) {
            ListNode temp = curr.next;
            curr.next = prev;
            prev = curr;
            curr = temp;
        }
        head.next = null;
        return prev;
    }
}

仔细观察代码,实际上是去掉了翻转链表,对k进行了更进一步的操作而已。相比解法一,代码更加的清晰。

相关文章

  • leetcode 链表 [C语言]

    21. 合并两个有序链表 合并两个有序链表 61. 旋转链表 (快慢指针) 61. 旋转链表 相关标签 : 链表 ...

  • 61. 旋转链表

    61. 旋转链表 问题 给定一个链表,旋转链表,将链表每个节点向右移动 个位置,其中 是非负数。 示例 1: 输...

  • [LeetCode]61. 旋转链表

    61. 旋转链表给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。示例:输入: 1-...

  • 61. 旋转链表

    61. 旋转链表 双指针,一个先走k步

  • 【D33】旋转链表 (LC61)

    61. 旋转链表[https://leetcode-cn.com/problems/rotate-list/] 给...

  • LeetCode:61. 旋转链表

    问题链接 61. 旋转链表[https://leetcode-cn.com/problems/rotate-lis...

  • 61.旋转链表

  • 61.旋转链表

    题目给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。 示例 1:输入: 1->2-...

  • 61. 旋转链表

    思路 找到旧的尾部并将其与链表头相连 old_tail.next = head,整个链表闭合成环,同时计算出链表的...

  • 61. 旋转链表

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

网友评论

    本文标题:61. 旋转链表

    本文链接:https://www.haomeiwen.com/subject/ixhqdqtx.html