返回
JavaScript重排链表——轻松搞定LeetCode 143
前端
2024-01-08 16:28:18
重排链表:一步步掌握 JavaScript 算法
序言
在软件开发领域,解决算法问题是至关重要的。LeetCode 143 题“重排链表”就是一道经典的算法题,考验我们的链表操作能力。本文将深入探讨这道题目的 JavaScript 解决方案,并提供详细的步骤和示例代码。
算法概述
重排链表算法的核心思想是将链表分成两半,然后将后半部分的节点插入前半部分的节点之间。具体来说,我们可以将其分解为以下步骤:
- 链表分割: 将链表从中间分割为两半,前半部分长度为 n/2,后半部分长度为 n/2(或 n/2+1,如果链表长度为奇数)。
- 后半部分反转: 将后半部分的链表反转,以便节点顺序与前半部分相反。
- 合并链表: 将反转的后半部分链表插入前半部分链表的节点之间,形成一个新的重排链表。
代码示例
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* Given a singly linked list L: L0→L1→…→Ln-1→Ln,
* reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→…
*
* You may not modify the values in the list's nodes. Only nodes themselves may be changed.
*
* Example 1:
*
* Given 1->2->3->4, reorder it to 1->4->2->3.
* Example 2:
*
* Given 1->2->3->4->5, reorder it to 1->5->2->4->3.
*
* @param {ListNode} head
* @return {void} Do not return anything, modify head in-place instead.
*/
const reorderList = function(head) {
if (!head || !head.next) {
return;
}
// Find the middle of the linked list.
let slow = head;
let fast = head.next;
while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
}
// Split the linked list into two halves.
const secondHalf = slow.next;
slow.next = null;
// Reverse the second half of the linked list.
let prev = null;
let current = secondHalf;
while (current) {
const next = current.next;
current.next = prev;
prev = current;
current = next;
}
// Merge the two halves of the linked list.
let firstHalf = head;
let secondHalfReversed = prev;
while (secondHalfReversed) {
const next1 = firstHalf.next;
const next2 = secondHalfReversed.next;
firstHalf.next = secondHalfReversed;
secondHalfReversed.next = next1;
firstHalf = next1;
secondHalfReversed = next2;
}
};
算法复杂度
- 时间复杂度: O(n),其中 n 是链表的长度。
- 空间复杂度: O(1),因为我们没有使用额外的空间。
常见问题解答
-
如何找到链表的中间节点?
使用快慢指针方法。快指针每次移动两步,慢指针每次移动一步。当快指针到达链表末尾时,慢指针正好指向中间节点。
-
如何反转链表?
使用迭代方法。将当前节点的 next 指针指向前一个节点,然后将前一个节点更新为当前节点。重复这个过程,直到到达链表末尾。
-
如何将两个链表合并?
迭代地遍历两个链表。对于每个节点,将后一个链表的第一个节点插入到前一个链表的当前节点的 next 指针之后。然后,更新后一个链表的第一个节点为其 next 指针。
-
如果链表的长度是奇数怎么办?
在这种情况下,后半部分的链表长度将比前半部分多一个节点。在合并链表时,将额外的节点插入到前半部分的最后一个节点之后。
-
如何测试算法?
创建具有不同长度和元素的链表,然后使用算法对它们进行重排。验证结果是否与预期的重排顺序一致。
总结
重排链表算法是链表操作中一个重要的概念。通过理解算法的步骤和实现细节,我们可以解决各种算法问题。本文提供了 JavaScript 算法的全面概述,包括示例代码、算法复杂度和常见问题解答。通过练习和理解,我们可以掌握链表操作技能,成为更熟练的软件开发人员。