leetcode hot100 19.删除链表的倒数第 N 个结点 快慢指针 medium


核心思路:制造"距离差"

要删除倒数第 nnn 个节点,需要找到它的前驱节点(即倒数第 n+1n+1n+1 个)。

  • 让 fast 指针先向前走 n+1n+1n+1 步。此时,fast (指向第n+1个节点)和 slow (指向第一个节点)之间隔了 nnn 个节点。
  • 同时移动 fast 和 slow,直到 fast 指向最后一个节点。此时 slow 恰好指向倒数第 n+1n+1n+1 个节点

这道题不需要创建新链表,所以不是:

python 复制代码
        prehead = ListNode(-1)
        dummy = prehead
	
			... ...

            # 建立新节点并移动指针
            dummy.next = ... ...
            dummy = dummy.next

重组旧链表,只需要新建一个 prehead 节点,指向链表

python 复制代码
        prehead = ListNode(-1)
        prehead.next = head  
        ... ...

		return prehead.next

直接返回head不行吗,为什么要prehead = ListNode(-1)

prehead.next = head 返回prehead.next:
核心原因:头节点也是会被删除的

假设链表是 1, 2,要删除倒数第 2 个(也就是删除 1):

  1. prehead 指向 1。
  2. 经过计算,slow 停在 prehead 上。
  3. 执行 slow.next = slow.next.next(即 prehead.next = 2)。
  4. 此时:head 变量依然指向 1。prehead.next 指向 2。

如果 return head,结果是 1, 2(错误); 如果 return prehead.next,结果是 2(正确)

"哑节点" (Dummy Node) 的作用

  • 防止"丢头":如上所述,处理头节点被删除的情况。、、
  • 空链表保护:当链表被删空时,prehead.next 会正确返回 None,而直接操作 head 可能会导致空指针引用报错

时间复杂度 :O(N)O(N)O(N)

虽然有两个循环(for 和 while),但指针一共只从头走到尾一次。
空间复杂度:O(1)O(1)O(1)

只额外申请了 prehead, fast, slow 这几个引用空间。

python 复制代码
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:

        # 用于指向新链表
        prehead = ListNode(-1)
        prehead.next = head  # 这一步是修复报错的关键

        # 用于操作旧链表
        fast = slow = prehead
        
        # fast先走n+1步
        for i in range(n+1):
            fast = fast.next

        # 同时移动 fast 和 slow,直到 fast 指向最后一个节点
        # 此时 slow 恰好指向倒数第 n+1 个节点
        while fast:
            slow = slow.next
            fast = fast.next

        # 倒数第 n+1 个节点,应该指向:倒数第 n+2 个节点
        #(跳过倒数n)
        tmp = slow.next.next
        slow.next = tmp

        return prehead.next
        
相关推荐
To_OC5 天前
LC 207 课程表:刚学图论那会儿,我连这是拓扑排序都没看出来
javascript·算法·leetcode
To_OC5 天前
LC 208 实现 Trie 前缀树:曾被名字劝退,写完发现是送分题
javascript·算法·leetcode
To_OC6 天前
LC 994 腐烂的橘子:人人都说是 BFS 入门题,我却写了三遍才过
javascript·算法·leetcode
To_OC6 天前
LC 200 岛屿数量:经典 DFS 入门题,我第一次写居然连方向都搞错了
javascript·算法·leetcode
To_OC7 天前
LC 128 最长连续序列:别上来就排序,O (n) 解法才是这题的灵魂
javascript·算法·leetcode
To_OC9 天前
LC 49 字母异位词分组:想到哈希表很简单,选对 key 才是精髓
javascript·算法·leetcode
To_OC10 天前
LC 1 两数之和:面试第一道必考题,暴力解法直接被面试官 pass
javascript·算法·leetcode
想吃火锅100516 天前
【leetcode】121.买卖股票的最佳时机js/c++
算法·leetcode·职场和发展
凌波粒16 天前
LeetCode--491.递增子序列(回溯算法)
数据结构·算法·leetcode
退休倒计时16 天前
【每日一题】LeetCode 146. LRU 缓存 TypeScript
算法·leetcode·缓存·typescript