旋转链表: leetcode地址
先来看下题
给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。
分析下
-
向右移动K个节点, 当K大于head长度的时候会再次重新走一下 所以我们向右移动
k的步数是k % 链表的长度, 相当于我们需要把后的k % n 个移动到链表前 -
看下初试做的动画演示
-
文字说明下:
- k步数可以是很大,根据提议我们移动的步数: 先获取链表长度, 然后 对 k % n 取余数就是步数
- 当前指针我们需要走到 步数移动的开始 所以 cur.next 循环 n - k % n 次, 可以的得到后面
k % n - 此时我们需要把最后节点的指针指向我们的头节点, 此时当前节点指针指向head的头结点
- 然后再走n - k % n 步, 截取后面的节点 使 当前指针是null
代码
function rotateRight(head, k) {
// 先处理一些特殊情况
if (head === null || head.next === null || k === 0) return head
// 先拿到head的长度
let n = 0
let cur = head
while(cur) {
cur = cur.next
n++
}
// 取余 获取 步数
const step = n - k % n
// step === n 相当于k === 0
if (step === n) return head
// 重置下cur
cur = head
for (let i = 0; i < step; i++) {
cur = cur.next
}
// 这里cur 就是我们需要放到链表头部的部分
// 把cur的尾结点指向head
let tmp = cur
while(cur.next) {
cur = cur.next
}
cur.next = head
for(let i = 0; i < step; i++) {
cur = cur.next
}
cur.next = null
// 这里我们的tmp就是旋转后的链表
return tmp
}
官方的解法
- 官方给的题解明显更好 - 是原链表成环(尾结点的next指向头节点),然后移动step下 然后截断
- 获取head的长度方法不同 int n = 0,让尾结点的next指向头节点 成环
- 保存截断后的链表 就是我们的结果
- 时间复杂度O(n), 最多完整的循环两次
- 自己的解法
- 整体大致思路差不太多
- 我是通过拼接和截断来做
- 时间复杂度O(2n) 比官方题解多遍历一整遍
- 得到长度n
- 第一次走step + cur走到next是空(n - step) 这部分是n
- 然后再次走了step
- 我这是暴力中的暴力解法了