题目
给定一个链表,旋转链表,将链表每个节点向右移动 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
解答
解法一:连成环再分割
具体步骤如下:
- 首先找到尾部,并计算出链表的长度。
- 连接尾部和头部从而形成环。
- 计算到达环链断点处所需要的步长( k = n - k % n )。
- 找到断点,切开环链即可。
代码
/**
* 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) return null;
// 计算出链表的长度
int n = 1;
ListNode tail = head;
while(tail.next != null) {
tail = tail.next;
n ++;
}
// 形成环
tail.next = head;
// 找到断点
k = n - k % n;
while(k -- > 0) {
tail= tail.next;
}
// 从断点处断开环链
head = tail.next;
tail.next = null;
return head;
}
}
结果
解法二:分两段再拼接
首先介绍两个很通用的方法:
- split 方法:将前 k 个元素截掉,返回后半段。
- last 方法:获取链表的尾部结点。
然后就可以使用他们完成本题了:
- 首先计算出链表长度
- 找到断点,获取到后半部分。
- 获取后半部分的最后一个元素,让其 next 为 head 即可。
代码
/**
* 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) return null;
int n = 0;
for(ListNode p = head; p != null; p = p.next) {
n ++;
}
ListNode right = split(head, n - k % n);
if(right == null) return head;
last(right).next = head;
return right;
}
private ListNode split(ListNode head, int k) {
ListNode p = head;
while(-- k > 0) {
p = p.next;
}
ListNode res = p.next;
p.next = null;
return res;
}
private ListNode last(ListNode head) {
ListNode p = head;
while(p != null && p.next != null) {
p = p.next;
}
return p;
}
}