第4章 数据结构与算法高频题

本章聚焦面试中最常考的数据结构与算法题目,包括数组、链表、树、哈希、排序、动态规划。掌握核心思路和回答框架,能帮助你在面试中快速拆解问题、清晰表达方案。

理解题意 确定输入输出 选择数据结构 数组/链表/哈希/树 设计算法 双指针/DP/排序 复杂度分析 时间/空间 测试边界 空/单节点/极端

📊 常见数据结构操作时间复杂度对比

数据结构存储方式访问(索引)插入/删除(头/尾)查找
数组连续内存O(1)O(n)O(n)
链表(单链)非连续指针链接O(n)O(1)(已知位置)O(n)
哈希表数组+链表/红黑树—O(1)平均O(1)平均
二叉搜索树(平衡)树节点O(log n)O(log n)O(log n)
堆(二叉堆)数组模拟完全二叉树O(1)(顶)O(log n)O(n)
面试建议:遇到算法题先确定核心数据结构,然后套用经典解法(双指针、滑动窗口、递归DP等),最后注意边界条件。

🧩 面试问题:如何判断一个链表是否有环?

面试官考察点:

  • 链表遍历与指针操作基本功
  • 双指针(快慢指针)技巧
  • 边界条件处理(空链表、单节点)

回答框架:

  1. 判断链表为空或只有一个节点,直接返回无环。
  2. 定义快慢指针,快指针每次走两步,慢指针每次走一步。
  3. 若快慢指针相遇则有环;若快指针走到None则无环。

示例回答:

def has_cycle(head):
    slow = fast = head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
        if slow == fast:
            return True
    return False

可能追问:

  • 如何找到环的入口节点?(快慢指针相遇后,让一个指针从头开始,步长1,再次相遇点即入口)
  • 如果链表很长,内存有限怎么优化?(考虑使用集合记录已访问节点,但空间O(n))
🚨 避坑提醒:忘记检查 fast.next 会造成空指针异常;循环条件必须同时判断 fast 和 fast.next。

🧩 面试问题:给定一个整数数组和一个目标值,找出数组中两个数之和等于目标值的索引。

面试官考察点:

  • 哈希表应用(空间换时间)
  • 遍历与查表优化
  • 对重复元素的处理

回答框架:

  1. 初始化哈希表,键为元素值,值为索引。
  2. 遍历数组,对当前元素x,计算补数target-x。
  3. 若补数已在哈希表中,返回对应索引。
  4. 否则将当前元素加入哈希表。

示例回答:

def two_sum(nums, target):
    seen = {}
    for i, val in enumerate(nums):
        complement = target - val
        if complement in seen:
            return [seen[complement], i]
        seen[val] = i
    return []

可能追问:

  • 如果数组已排序,如何优化?(双指针法,O(1)空间)
  • 如果数组中存在重复元素,怎么保证返回唯一解?(题目通常假定只有唯一解;否则需额外判断)
🚨 避坑提醒:不能先全部存入哈希表再遍历,可能重复使用同一元素(如[3,3] target=6);必须边遍历边检查。

🧩 面试问题:实现斐波那契数列,要求时间复杂度 O(n) 且空间 O(1)。

面试官考察点:

  • 递归 vs 迭代理解
  • 动态规划状态压缩思想
  • 大数处理意识

回答框架:

  1. 边界:n=0返回0,n=1返回1。
  2. 用两个变量a=0,b=1滚动计算。
  3. 循环n-1次,每次更新a,b为b,a+b。
  4. 最后返回b。

示例回答:

def fib(n):
    a, b = 0, 1
    for _ in range(n):
        a, b = b, a + b
    return a

可能追问:

  • n非常大(如10^7)时,Python还能承受吗?(Python大整数无溢出,但速度变慢,可考虑矩阵快速幂)
  • 如何用矩阵幂将时间复杂度降到O(log n)?(使用斐波那契矩阵幂)
🚨 避坑提醒:注意循环次数;如果取n=0,应返回a(0),不要返回b;使用递归会导致指数级复杂度,面试时务必主动指出优化方案。