题目描述
给定一个链表,旋转链表,将链表每个节点向右移动 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;
}
}