题目
给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。
示例1
输入:head = [1,2,3,4,5], k = 2
输出:[4,5,1,2,3]
思路
这个题其实用双指针很简单;复杂点在于k有可能会大于链表的长度。双指针的思路是:快指针先到达第k+1个节点,然后满指针指向head,两个指针同时前进直到快指针到达链表尾部。此时的满指针的next节点就是新的链表头、快指针指向原来的head即可。
在k大于链表长度的情况下,计算出(k = k mod list_length), 依然按照上面的思路进行即可。
code
class ListNode {
int val;
ListNode next;
ListNode() {
}
ListNode(int val) {
this.val = val;
}
ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
class Solution {
public ListNode rotateRight(ListNode head, int k) {
if (head == null || head.next == null || k == 0) return head;
ListNode pre = head;
int count = 1;
while (pre.next != null && count < k + 1) {
pre = pre.next;
count++;
}
// 链表到达尾部,重新计算k之后,快节点重新前进到k+1处
if (count != k + 1) {
k = k % count;
if (k == 0) {
return head;
}
pre = head;
count = 1;
while (pre.next != null && count < k + 1) {
pre = pre.next;
count++;
}
}
// 两个节点同时前进,直到快节点到达链表尾部
ListNode post = head;
while (pre.next != null) {
pre = pre.next;
post = post.next;
}
// 生成新链表
ListNode result = post.next;
post.next = null;
pre.next = head;
return result;
}
}
官方思路
官方思路更好的一个点是,它的思路顺畅性和复杂度的稳定性,需要更少的考虑一些特殊情况。首先它会直接遍历到节点尾部,直到链表的长度。然后也是计算k mod list_length,然后将链表首尾相连,继续遍历到list_length - (k mod list_length)的地方,断开此处的链接,生成新的链表。
代码如下:
class Solution {
public ListNode rotateRight(ListNode head, int k) {
if (k == 0 || head == null || head.next == null) {
return head;
}
int n = 1;
ListNode iter = head;
while (iter.next != null) {
iter = iter.next;
n++;
}
int add = n - k % n;
if (add == n) {
return head;
}
iter.next = head;
while (add-- > 0) {
iter = iter.next;
}
ListNode ret = iter.next;
iter.next = null;
return ret;
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/rotate-list/solution/xuan-zhuan-lian-biao-by-leetcode-solutio-woq1/
来源:力扣(LeetCode)
总结
官方解法的好处是思路的流畅性和复杂度的稳定性。但是在k< list_length的情况下,其实复杂度更高一些。
时间复杂度都是O(N)
空间复杂度都是O(1)