从被追问到被点赞:我靠“哨兵+快慢指针”展示了面试官真正想看的代码思维

面试高频链表题精讲:从哨兵节点到快慢指针

在算法面试中,链表 是一类非常经典的数据结构题型。它不像数组那样支持随机访问,但正因如此,很多操作都需要我们对指针(引用)有精准的控制。本文将通过四道典型题目,带你系统掌握链表处理中的两大核心技巧:哨兵节点(Dummy Node) 和 快慢指针(Fast & Slow Pointers) 。


一、删除链表中的指定节点:为什么需要哨兵节点?

题目描述

给定一个单链表的头节点 head 和一个值 val,删除链表中所有值等于 val 的节点,并返回新的头节点。

力扣:LCR 136. 删除链表的节点 - 力扣(LeetCode)

初步解法(不使用哨兵)

js 复制代码
function remove(head, val) {
  // 特殊处理头节点
  if (head && head.val === val) {
    return head.next;
  }
  let cur = head;
  while (cur.next) {
    if (cur.next.val === val) {
      cur.next = cur.next.next;
      break; // 假设只删第一个匹配项
    }
    cur = cur.next;
  }
  return head;
}

面试官反问:

"你为什么要单独判断头节点?能不能统一处理?"

这是一个非常关键的问题!因为头节点没有前驱节点,所以当我们想"让前一个节点跳过当前节点"时,头节点就成了特例。

引入哨兵节点(Dummy Node)

哨兵节点是一个人为添加的假节点 ,通常放在链表头部,其作用是消除边界条件的特殊处理。

js 复制代码
function remove(head, val) {
  const dummy = new ListNode(0);
  dummy.next = head;
  let cur = dummy;
  while (cur.next) {
    if (cur.next.val === val) {
      cur.next = cur.next.next;
      break;
    }
    cur = cur.next;
  }
  return dummy.next; // 返回真正的头节点
}

✅ 优势:

  • 不再需要单独判断头节点是否为待删节点;
  • 所有节点都变成了"中间节点",逻辑统一;
  • 即使链表为空或全被删完,也能安全返回。

二、反转链表:哨兵 + 头插法

题目描述

反转一个单链表。

力扣:206. 反转链表 - 力扣(LeetCode)

解法思路

我们可以利用哨兵节点作为新链表的头 ,然后遍历原链表,每次把当前节点插入到哨兵之后 ------这就是头插法。

js 复制代码
function reverseList(head) {
  const dummy = new ListNode(0); // 哨兵,dummy.next 指向已反转部分的头
  let cur = head;
  while (cur) {
    const next = cur.next;       // 1. 保存下一个节点
    cur.next = dummy.next;       // 2. 当前节点指向已反转部分的头
    dummy.next = cur;            // 3. 更新反转部分的新头
    cur = next;                  // 移动到原链表下一节点
  }
  return dummy.next;
}

🔍 关键理解:

  • dummy 始终不动,它的 next 指向当前已反转链表的头;
  • 每轮操作把 cur 插到最前面,实现"头插";
  • 三步操作顺序不能乱,否则会断链。

💡 虽然这道题也可以用递归或双指针(prev/cur)实现,但哨兵+头插法提供了一种清晰、不易出错的迭代思路。


三、判断链表是否有环:从哈希表到快慢指针

题目描述

给定一个链表,判断其中是否存在环。

力扣:141. 环形链表 - 力扣(LeetCode)

解法一:哈希表(空间换时间)

js 复制代码
let hash = new Map();
let temp =head;
while(temp)
 {
   if(hash.has(temp))
    return true;
   else
    hash.set(temp,1);
  temp=temp.next;
 }
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

面试官追问:

"能不能不用额外空间?"

解法二:快慢指针(Floyd 判圈算法)

核心思想:如果链表有环,快指针(每次走两步)一定会在环内追上慢指针(每次走一步)。

js 复制代码
function hasCycle(head) {
  let slow = head;
  let fast = head;
  while (fast && fast.next) {
    slow = slow.next;         // 慢指针走1步
    fast = fast.next.next;    // 快指针走2步
    if (slow === fast) {      // 比较引用地址(同一内存)
      return true;
    }
  }
  return false;
}

✅ 优势:

  • 空间复杂度 O(1);
  • 时间复杂度 O(n);
  • 是链表环检测的标准解法。

🌟 快慢指针不仅用于判环,还可用于找环入口、求中点、删除倒数第 N 个节点等。


四、删除链表的倒数第 N 个节点:哨兵 + 快慢指针的完美结合

题目描述

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

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

解法思路

  1. 使用哨兵节点避免头节点被删的边界问题;
  2. 快指针先走 n 步;
  3. 然后快慢指针同步移动 ,当快指针到达末尾时,慢指针正好在倒数第 n 个节点的前一个;
  4. 执行删除操作。
js 复制代码
const removeNthFromEnd = function(head, n) {
  const dummy = new ListNode(0);
  dummy.next = head;
  let fast = dummy;
  let slow = dummy;

  // 快指针先走 n 步
  for (let i = 0; i < n; i++) {
    fast = fast.next;
  }

  // 快慢指针一起走,直到 fast 到达最后一个节点
  while (fast.next) {
    fast = fast.next;
    slow = slow.next;
  }

  // 此时 slow 指向倒数第 n 个节点的前一个
  slow.next = slow.next.next;

  return dummy.next;
};

🎯 为什么需要哨兵?

  • 如果要删除的是头节点 (比如链表长度为 5,n=5),那么 slow 需要停在"头节点之前";
  • 没有哨兵的话,slow 无法指向 null 的前驱;
  • 哨兵确保 slow 始终有效,且 slow.next 可安全删除。

总结:链表面试两大法宝

技巧 适用场景 核心价值
哨兵节点(Dummy) 删除、插入、反转等涉及头节点的操作 消除边界条件,统一逻辑
快慢指针 判环、找中点、倒数第 N 个节点 O(1) 空间解决距离/位置问题

在实际面试中,先写出朴素解法(如哈希表) ,再根据面试官提示优化到快慢指针 ,能体现你的思维层次;而哨兵节点则是写出健壮、简洁代码的关键技巧。


希望这篇文章能帮你打通链表题的任督二脉!下次遇到链表题,先问自己两个问题:

  1. 要不要加哨兵? → 避免头节点特殊处理
  2. 能不能用快慢指针? → 解决"倒数"、"中点"、"环"等问题

祝你面试顺利,Offer 收割!🎉

相关推荐
yi0118 小时前
LeetCode 219:存在重复元素 II——哈希表记录“最近一次出现的位置”
数据结构·人工智能·笔记·python·算法·leetcode·哈希表
程序员Sunday8 小时前
JavaScript 事件循环面试题,宏任务与微任务怎么执行|Sunday面试指南
开发语言·javascript·面试·校招·事件循环·程序员sunday
YangYang9YangYan8 小时前
2027 秋招|数据科学与大数据技术面试项目价值回答思路,告别纯代码描述
大数据·面试·职场和发展
默_笙9 小时前
🌊 向量库和 ES 都查不出"关系",我只好给奶茶建了一张人脉网
前端·javascript
邓江洲9 小时前
一道经典的 NSString 内存面试题
面试
思无邪6610 小时前
用 AI 做 JS 逆向:从抓包到复现的完整方法论
开发语言·javascript·人工智能
灯澜忆梦10 小时前
【面向对象编程C++】| 基础语法
java·c++·算法
小蒋观天下10 小时前
专项方案:大场景港口AI安防、多干扰环境下的算法调优与落地实操
人工智能·深度学习·算法·安全·机器学习·计算机视觉·ai大模型
Evand J11 小时前
【电机滤波例程5】渐消因子自适应扩展卡尔曼滤波(EKF),MATLAB。PMSM负载突变下的状态估计。附下载链接
算法·matlab
H.莓飛11 小时前
【数据结构】二叉树_OJ题
linux·开发语言·数据结构·算法