题目描述
给定一个链表,旋转链表,将链表每个节点向右移动 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
分析
之前做过一个题,是旋转数组,把数组按要求向右循环移位。在旋转数组中,用到了按索引反转数组的一个辅助方法,先把数组整体反转,再分为两部分分别反转,就可以得到结果了。这个方法在链表中就不太适用了,因为链表获取索引很不方便。但是可以借鉴一下大致的思路,依然是把链表分成两部分,把后面一截移到前面一截的前面,不就完成了所谓的循环右移吗?
对此,有两种方法:
- 双指针+哑节点
 - 单指针
 
说是两种方法,但其实第二种方法是第一种方法的改进,本质上都是刚才所说的把链表分成两部分,把后面一截移到前面一截的前面。
双指针+哑节点
- 新建一个哑节点放在原链表前面
 - 新建两个指针
first,second指向哑节点 - 先把
first移动到最后一个节点,同时记录下链表的长度len - 再把
second移动到第len-k个元素的位置 - 执行旋转操作。具体分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。具体步骤如下:
- 新建一个指针
p,指向链表头部head - 移动
p到链表尾部,并记录链表长度 - 形成环状(
p.next = head) p移动到分界点,即p后面有k个元素head移动到p.next- 断开
p和head的链接 
跟双指针一样,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;
    }
}