一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第8天,点击查看活动详情
1. 题解
将链表移动k个位置,需要注意的有两点
- 当
k大于链表长度时: 比如下图的链表,k可以是2也可以是7,只要k满足链表长度len * N + 2旋转结果都是一样的。所以要知道对于任意k,链表实际旋转的最小位置是多少。
-
当进行旋转操作时,如果把要旋转的部分看成一个组,剩下的看一个成组,就很类似链表中两个节点的反转。主要是找到几个点的位置:
-
因为可能会修改头节点的位置,需要哨兵节点: 要链接旋转区域的头节点
-
要旋转区域的前一个节点
pre:- 找到旋转区域的头节点
pre.next - 防止形成有环链表,需要置为
null
- 找到旋转区域的头节点
-
最后一个节点
last: 链接原来的头节点
-
根据上图,代码就很好写了:
function rotateRight(head: ListNode | null, k: number): ListNode | null {
// 特殊情况:如果为null,或者只有一个节点,或者移动位置为0都直接返回
if (head === null || head.next === null || k === 0) return head
let cur = head
let len = 0
// 计算总长度
while(cur) {
len++
cur = cur.next
}
// 真实移动的位置
const realRotateOffset = k % len
// 如果为0,还是直接返回
if (realRotateOffset === 0) {
return head
}
// 哨兵节点
const dummy = new ListNode(-1, head)
let preOffset = len - realRotateOffset
let pre = dummy
while(preOffset-- > 0) {
pre = pre.next
}
let next = pre.next
// 防止产生有环列表 上图中的第三条连接线
pre.next = null
let last = next
while(last && last.next !== null) {
last = last.next
}
// last -> dummy.next 上图中的第二条连接线
last.next = dummy.next
// dummy --> pre.next 上图中的第一条连接线
dummy.next = next
return dummy.next
};
2. 复杂度
- 时间复杂度: 循环了两次,
O(N) - 空间复杂度:缓存几个变量的数据,
O(1)