LeetCode 19:删除链表的倒数第 N 个结点

125 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情

LeetCode 19:删除链表的倒数第 N 个结点

题目描述

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

解题思路

思路一:利用栈

我们可以在遍历链表的同时将所有节点依次入栈。根据栈「先进后出」的原则,我们弹出栈的第 n 个节点就是需要删除的节点,并且目前栈顶的节点就是待删除节点的前驱节点。这样一来,删除操作就变得十分方便了。

利用数组实现栈先进后出方法为push---入栈和pop---出栈。
添加一个dummy node(哑节点),它的next 指针指向链表的头节点。这样一来,我们就不需要对头节点进行特殊的判断了。

解题代码如下:

/**
 * @param {ListNode} head
 * @param {number} n
 * @return {ListNode}
 */
var removeNthFromEnd = function(head, n) {
  let dummy = new ListNode();
  dummy.next = head;
  let cur = dummy, stack = [] ;
  while (cur !== null) {
    stack.push(cur);
    cur = cur.next;
  }
  for (let i = 0; i < n; ++i) {
    stack.pop();
  }
  let prev = stack[stack.length - 1];
  prev.next = prev.next.next;
  return dummy.next;
}

时间复杂度: O(n);

空间复杂度: O(n);

思路二:利用快慢指针

解析分解:
1.需要删除倒数第n个节点, 那么我们需要知道倒数n-1个节点, 执行删除的操作是node.next=node.next.next, 即将当前节点的next指针指向当前节点的下一个节点的下一个节点;
2. 设置快慢两个指针, 快指针先走n + 1步,然后快慢指针一次走一步,当快指针遍历到链表的末尾时,慢指针就刚好处于倒数第n-1个节点;
3. 执行删除,返回dummy节点的next指针即可

/**
 * @param {ListNode} head
 * @param {number} n
 * @return {ListNode}
 */
var removeNthFromEnd = function(head, n) {
  let dummy = new ListNode();
  dummy.next = head;
  let fast = dummy, slow = dummy;
  // 快指针先走n + 1步
  for (let i = 0; i <= n; i++) {
      fast = fast.next;
  }
  // 快慢指针一次走一步,直到快指针走到头 
  while(fast !== null) {
      fast = fast.next;
      slow = slow.next;
  }
  slow.next = slow.next.next;
  return dummy.next;
};

时间复杂度: O(n);

空间复杂度: O(1);

参考资料

删除链表的倒数第N个节点 - 删除链表的倒数第 N 个结点 - 力扣(LeetCode)