给你一个链表的头节点 head
,旋转链表,将链表每个节点向右移动 k 个位置。
每旋转一次,实际上就是将链表的最后一个节点指向链表的 head
,并且将链表的倒数第二个节点指向 null
分析
值得注意的是,链表的旋转是一次次循环的操作,如果链表循环的次数等于链表的长度,那么实际旋转后的效果和没有旋转的链表是一样的
如上图,链表长度为3,那么当链表旋转3次之后,就和原链表保持一致。
由此可知:
当链表旋转次数等于 链表长度 + 1时,就等同于链表旋转了1次
链表旋转次数等于 链表长度 + m时, 就等同于链表旋转了 m次 , m < 链表长度
设链表长度为 n,旋转 k 次
如此一来就可以节省多次不必要的旋转,理论上的旋转次数一定是小于链表长度的,且次数等于 k % n , 遍历到该节点的次数就为 count = n - k % n
如何进行链表的旋转操作?
1.计算链表长度
2.计算理论需要旋转链表的次数
3.计算遍历到 "需要变为head
" 节点的次数
4.将链表首尾相接
5.遍历 链表,更改 head 节点
6.断开首尾相接,最终得到旋转后的链表
代码实现:
class NodeList {
constructor(val) {
this.val = val
this.next = null
}
//添加链表的新增节点方法
append(val) {
let currnt = this
let node = new NodeList(val)
while (currnt.next) {
currnt = currnt.next
}
currnt.next = node
}
// 打印
print() {
let current = this
let res = []
while (current) {
res.push(current.val)
current = current.next
}
console.log(res)
}
}
let node1 = new NodeList(1)
node1.append(2)
node1.append(3)
node1.append(4)
node1.append(5)
const f = (list, k) => {
// 计算 链表长度 n
let n = 1;
let current = list
while (current.next) {
current = current.next
n++
}
// 计算和实际需要旋转次数同样效果的理论旋转次数
let count = n - k % n
// 如果 count === 0 ,那么实际上就和不需要旋转效果一致
if (count === 0) {
return list
}
// 链表首尾相接
current.next = list
// 找到旋转 count 次数后对应的理论 head 节点
while (count) {
current = current.next
count--
}
// current 即为最终搜需要的链表最后一个节点,但是还是首尾相接的,所以 current.next 即为链表 head,再将 current.next = null 切断首尾相连
const res = current.next
current.next = null
return res
}
const res = f(node1, 6)
res.print()
输出结果
[5, 1, 2, 3, 4]