旋转链表
给你一个链表的头节点 head
,旋转链表,将链表每个节点向右移动 k
个位置。
示例 1:
输入:head = [1,2,3,4,5], k = 2 输出:[4,5,1,2,3]
示例 2:
输入:head = [0,1,2], k = 4 输出:[2,0,1]
提示:
- 链表中节点的数目在范围
[0, 500]
内 -100 <= Node.val <= 100
0 <= k <= 2 * 109
解题思路
从题目的要求来看,我们需要将整条链表往右移动k个位置;也就是会把链表尾部的k个节点,依次往链表头上添加,在提示中,给出了链表值的范围,其实这个条件是无效的,因为,我们不会对链表的值进行操作,有用的条件是提示中的链表的节点数和k的取值范围。
我们确定解题思路:首先我们先将链表首尾相连,然后按照要求,依次遍历节点,截断位置。那么应该截断的位置在哪里呢?我们推导一下:
- 如示例1,总共5个节点,向右移动2个位置;最后,链表首位是第4个节点,链表尾部是第3个节点,所以需要遍历到第5 - 2 = 3个节点作为尾部,下一个节点作为头部。
- 如示例2,总共3个元素,向右移动4个位置,这个时候注意,移动的位置数是大于链表的长度的;如果我们移动3个位置,相当于不变,所以移动4个位置相当于是只移动了4 - 3 = 1个位置;所以需要遍历到第(3 - 4%3)= 2个节点作为尾部,下一个节点作为头部。
具体代码如下:
/**
* 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;
int len = 0;
ListNode node = head;
// 遍历链表尾部
for(len = 1; node.next != null; len++)node = node.next;
node.next = head; // 首尾相连
ListNode pre = head;
for(int i = 1; i < len - k%len; i++)pre = pre.next;
head = pre.next;
pre.next = null;
return head;
}
}
复杂度分析
- 时间复杂度:O(n),我们最少也需要遍历链表一次;最糟糕的情况下,当链表的长度n等于k+1时,我们需要遍历链表n + n - 1次。
- 空间复杂度:O(1),我们只需要常数的空间,来存储len、node、pre即可。