LeetCode 热题 100:链表专题解析

83 阅读4分钟

LeetCode 热题 100:链表专题解析

本文将详细讲解两道经典的 LeetCode 链表题目:

  • 160. 相交链表
  • 206. 反转链表

我们将从题目分析、解题思路、代码实现到复杂度分析进行全面解析,帮助你深入理解链表操作的核心技巧。


🧩 题目一:160. 相交链表

🔍 题目描述

给你两个单链表的头节点 headAheadB,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null

注意:保证整个链式结构中不存在环,且函数返回后链表结构必须保持不变。

📌 示例图示

A: a1 → a2 → c1 → c2 → c3B: b1 → b2 → b3 → c1 → c2 → c3

相交于节点 c1


💡 解题思路

方法一:双指针法(推荐)

核心思想
让两个指针分别遍历两个链表,当一个指针到达末尾时,跳转到另一个链表的头部继续遍历。这样可以确保两个指针走过的总长度相同。

假设:

  • 链表 A 的非公共部分长度为 a
  • 链表 B 的非公共部分长度为 b
  • 公共部分长度为 c

那么:

  • 指针 A 走了 a + c + b
  • 指针 B 走了 b + c + a

两者最终会同时到达交点或同时为 null

✅ 优势:
  • 时间复杂度 O(m+n)
  • 空间复杂度 O(1)
  • 不需要额外存储空间

✅ JavaScript 实现

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

/**
 * @param {ListNode} headA
 * @param {ListNode} headB
 * @return {ListNode}
 */
var getIntersectionNode = function(headA, headB) {
    let pA = headA;
    let pB = headB;

    while (pA !== pB) {
        pA = pA === null ? headB : pA.next;
        pB = pB === null ? headA : pB.next;
    }

    return pA; // 返回相交节点,若无则为 null
};

📊 复杂度分析

项目分析
时间复杂度O(m + n),m 和 n 分别是两个链表的长度
空间复杂度O(1),仅使用常量级额外空间

🧠 小贴士

  • 这种“双指针交替遍历”的技巧在处理链表长度不一致问题时非常有效。
  • 若链表有环,需先判断是否有环再求交点(但本题已说明无环)。

🧩 题目二:206. 反转链表

🔍 题目描述

给你单链表的头节点 head,请你反转链表,并返回反转后的链表。

📌 示例

输入: head = [1,2,3,4,5]
输出: [5,4,3,2,1]


💡 解题思路

方法一:迭代法(最常用)

核心思想
逐个修改每个节点的 next 指针,使其指向前一个节点。

我们用三个变量:

  • prev:前一个节点
  • curr:当前节点
  • nextTemp:保存下一个节点(防止丢失)

每一步操作如下:

  1. 保存 curr.next
  2. curr.next 指向 prev
  3. 移动 prevcurr
🔄 流程示意
1 → 2 → 3 → null
prev = null, curr = 1
nextTemp = 2
curr.next = prev → 1 → null
prev = 1, curr = 2
...

最终结果:5 → 4 → 3 → 2 → 1 → null


✅ JavaScript 实现

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

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function(head) {
    let prev = null;
    let curr = head;

    while (curr !== null) {
        let nextTemp = curr.next; // 保存下一个节点
        curr.next = prev;         // 反转指针
        prev = curr;              // 移动 prev
        curr = nextTemp;          // 移动 curr
    }

    return prev; // prev 是新的头节点
};

📊 复杂度分析

项目分析
时间复杂度O(n),n 是链表长度
空间复杂度O(1),只用了常量级额外空间

🧠 小贴士

  • 初学者容易忘记保存 next 节点,导致链表断裂。
  • 可以画图辅助理解指针变化过程。
  • 递归方法虽然简洁,但空间复杂度为 O(n),不如迭代高效。

🎯 总结对比

题号名称核心技巧时间复杂度空间复杂度
160相交链表双指针交替遍历O(m+n)O(1)
206反转链表迭代指针翻转O(n)O(1)

✅ 学习建议

  1. 动手画图:链表题一定要画出指针移动过程,避免逻辑混乱。

  2. 边界情况:注意空链表、单节点等特殊情况。

  3. 多语言练习:尝试用 Python、Java、C++ 再写一遍,加深理解。

  4. 拓展思考

    • 如何判断链表是否有环?
    • 如何在 O(1) 空间内合并两个有序链表?

🚀 推荐进阶题目

    1. 环形链表
    1. 环形链表 II
    1. 合并两个有序链表
    1. 回文链表

通过掌握这两道基础链表题,你可以打下坚实的数据结构基础,为后续更复杂的算法题做好准备!

📌 坚持每日一题,轻松拿下 LeetCode!