[路飞]算法_旋转链表

130 阅读2分钟

旋转链表: leetcode地址

先来看下题

给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。

旋转链表exp1.png

旋转链表exp2.png

分析下

  • 向右移动K个节点, 当K大于head长度的时候会再次重新走一下 所以我们向右移动k的步数是 k % 链表的长度, 相当于我们需要把后的k % n 个移动到链表前

  • 看下初试做的动画演示

    xzlb1.gif

  • 文字说明下:

    1. k步数可以是很大,根据提议我们移动的步数: 先获取链表长度, 然后 对 k % n 取余数就是步数
    2. 当前指针我们需要走到 步数移动的开始 所以 cur.next 循环 n - k % n 次, 可以的得到后面k % n
    3. 此时我们需要把最后节点的指针指向我们的头节点, 此时当前节点指针指向head的头结点
    4. 然后再走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下 然后截断
    1. 获取head的长度方法不同 int n = 0,让尾结点的next指向头节点 成环
    2. 保存截断后的链表 就是我们的结果
    3. 时间复杂度O(n), 最多完整的循环两次
  • 自己的解法
    1. 整体大致思路差不太多
    2. 我是通过拼接和截断来做
    3. 时间复杂度O(2n) 比官方题解多遍历一整遍
      • 得到长度n
      • 第一次走step + cur走到next是空(n - step) 这部分是n
      • 然后再次走了step
    4. 我这是暴力中的暴力解法了