返回

倒计时的紧张感——谈LeetCode第19题的解决方案

前端

导语

当谈到算法和数据结构的经典习题时,LeetCode第19题——删除链表的倒数第N个节点绝对榜上有名。

它的巧妙设计让无数程序员绞尽脑汁,寻找最佳的解决方案。在本文中,我们将踏上这次奇妙的编程旅程,使用JavaScript解锁这个难题。

解析题目:倒数计时

题目

给你一个链表,删除链表的倒数第n个节点,并且返回链表的头结点。

例如,给定一个链表:

1->2->3->4->5
当n=2时,返回链表:

1->2->3->5

题目分析

让我们分解一下题目要求:

  • 给定一个链表,意味着我们正在处理一个线性数据结构。
  • 需要删除倒数第n个节点,这就意味着我们需要找到链表中从尾部数起第n个节点。
  • 删除节点后,我们需要返回修改后的链表的头结点。

解决方案:步步为营

算法概述

我们的解决方案采用双指针法,使用两个指针pre和cur分别指向虚头和头节点。

  1. 首先,我们需要让cur指针向前移动n步,以找到倒数第n个节点的位置。
  2. 然后,我们将pre和cur指针一起向后移动,直到cur指针指向null。此时,pre指针指向倒数第n个节点的前一个节点。
  3. 最后,我们将pre指针指向pre指针的下一个节点,也就是删除了倒数第n个节点后的链表。

代码示例

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * Given a linked list, remove the nth node from the end of the list and return its head.
 *
 * Example:
 * Given linked list: 1->2->3->4->5, and n = 2.
 * After removing the second node from the end, the linked list becomes 1->2->3->5.
 *
 * Note:
 * Given n will always be valid.
 *
 * @param {ListNode} head
 * @param {number} n
 * @return {ListNode}
 */
const removeNthFromEnd = (head, n) => {
  // Create a dummy node to simplify the code
  const dummy = new ListNode(0);
  dummy.next = head;

  // Initialize two pointers, pre and cur
  let pre = dummy;
  let cur = head;

  // Move cur pointer n steps ahead
  for (let i = 0; i < n; i++) {
    cur = cur.next;
  }

  // Move pre and cur pointers together until cur reaches the end of the list
  while (cur) {
    pre = pre.next;
    cur = cur.next;
  }

  // Delete the nth node from the end by skipping it
  pre.next = pre.next.next;

  // Return the head of the modified list
  return dummy.next;
};

复杂度分析

  • 时间复杂度:O(n),其中n是链表的长度。因为我们遍历了链表两次,一次是让cur指针移动n步,另一次是让pre和cur指针一起移动。
  • 空间复杂度:O(1),因为我们没有使用额外的空间。

结语

LeetCode第19题是一个经典的链表操作问题,希望本文清晰、详细的讲解对各位有所帮助。欢迎大家在评论区分享你们的解题思路和心得,共同提高编程技能。

LeetCode上的算法和数据结构练习非常具有挑战性,但只要你坚持不懈,不断积累经验,你一定会成为一名优秀的程序员!