JS链表旋转

187 阅读2分钟

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

image.png

image.png

每旋转一次,实际上就是将链表的最后一个节点指向链表的 head,并且将链表的倒数第二个节点指向 null

分析

值得注意的是,链表的旋转是一次次循环的操作,如果链表循环的次数等于链表的长度,那么实际旋转后的效果和没有旋转的链表是一样的

image.png

image.png

如上图,链表长度为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]