返回

化繁为简:利用 JavaScript 巧解链表旋转谜题

前端

在 JavaScript 中巧妙旋转链表

简介

在 JavaScript 的编程世界中,链表是一个常见的数据结构,它以其高效的插入和删除操作而闻名。然而,当我们需要旋转链表时,即将链表中的每个元素向右移动 k 个位置时,事情就会变得有点棘手。在本文中,我们将深入探讨如何在不破坏链表的情况下旋转链表,并提供易于理解的示例和代码。

旋转链表的本质

旋转链表的本质在于重新组织链表中元素的顺序。向右移动 k 个位置意味着我们将链表的前 k 个元素移动到链表的末尾。具体来说,我们将链表的第 k+1 个元素设为新的头部,并将原先的头部移动到新尾部之后。

JavaScript 中的链表旋转

为了在 JavaScript 中实现链表旋转,我们将遵循以下步骤:

  1. 确定旋转位置: 首先,我们需要确定需要移动的 k 个位置。
  2. 寻找新头部: 接下来,我们需要找到链表的第 k+1 个元素,它将成为新的头部。
  3. 断开新头部: 一旦我们找到了新头部,我们需要将其从链表中分离出来。
  4. 移动原头部: 现在,我们需要将原先的头部移动到新尾部之后。
  5. 连接新头部: 最后,我们将新头部连接到链表的开头。

示例代码

// 定义一个节点类
class Node {
  constructor(val) {
    this.val = val;
    this.next = null;
  }
}

// 定义一个链表类
class LinkedList {
  constructor() {
    this.head = null;
    this.tail = null;
    this.length = 0;
  }

  // 旋转链表
  rotate(k) {
    if (k <= 0 || k >= this.length) {
      return; // 无需旋转
    }

    let current = this.head;
    let count = 1;

    // 找到第 k+1 个节点
    while (count < k) {
      current = current.next;
      count++;
    }

    // 断开第 k+1 个节点
    const newHead = current.next;
    current.next = null;

    // 移动原头部
    let temp = this.head;
    this.head = newHead;
    while (temp.next) {
      temp = temp.next;
    }
    temp.next = this.tail;

    // 连接新头部
    this.tail = current;
  }
}

代码解析

  1. 我们定义了 Node 类表示链表中的节点,它包含一个 val 值和指向下一个节点的 next 指针。
  2. 我们定义了 LinkedList 类表示链表,它包含 head(头部)、tail(尾部)和 length(链表长度)。
  3. rotate 方法中,我们首先检查 k 是否有效,即是否在 1 到链表长度之间。
  4. 我们遍历链表,找到第 k+1 个节点,然后将其与链表分离。
  5. 我们将原先的头部移动到新尾部之后。
  6. 最后,我们连接新头部到链表的开头。

示例用法

const linkedList = new LinkedList();
linkedList.add(1);
linkedList.add(2);
linkedList.add(3);
linkedList.add(4);
linkedList.add(5);

console.log("原始链表:", linkedList.toString());
linkedList.rotate(2);
console.log("旋转后的链表:", linkedList.toString());

输出:

原始链表: 1 -> 2 -> 3 -> 4 -> 5
旋转后的链表: 4 -> 5 -> 1 -> 2 -> 3

结论

通过本文中介绍的方法,我们可以轻松地旋转 JavaScript 中的链表,从而重新组织元素顺序。无论是解决 LeetCode 问题还是处理实际应用程序中的链表,这种技术都是至关重要的。

常见问题解答

  1. 旋转链表的时间复杂度是多少?

    • 旋转链表的时间复杂度为 O(n),其中 n 是链表的长度。
  2. 空间复杂度是多少?

    • 旋转链表的空间复杂度为 O(1),因为我们没有创建任何新的节点。
  3. 旋转链表可以负数吗?

    • 当然可以。负数的 k 值表示向左旋转链表。
  4. 链表为空时,旋转链表会发生什么?

    • 如果链表为空,则旋转操作不会发生任何变化。
  5. 旋转链表是否会改变链表中的元素值?

    • 不,旋转链表不会改变链表中元素的值,只会改变它们的顺序。