数据结构与算法面试核心考点精要

💼 数据结构与算法面试核心考点精要

高频题型 · 代码模板 · 复杂度分析 · 避坑指南


🔑 一、数组与字符串

1.1 双指针技术

模板:左右指针(相向移动)
java 复制代码
int left = 0, right = arr.length - 1;
while (left < right) {
    if (condition) {
        // 处理逻辑
        left++;
        right--;
    } else if (arr[left] < target) {
        left++;
    } else {
        right--;
    }
}

适用场景 :两数之和、盛水最多容器、回文判断
时间复杂度 :O(n)
空间复杂度:O(1)

模板:快慢指针(同向移动)
java 复制代码
int slow = 0;
for (int fast = 0; fast < arr.length; fast++) {
    if (condition(arr[fast])) {
        arr[slow++] = arr[fast];
    }
}
return slow; // 新数组长度

适用场景 :移除元素、删除排序数组重复项
关键点slow 指向待写入位置,fast 遍历原数组


1.2 滑动窗口

模板:固定窗口大小
java 复制代码
int left = 0, sum = 0, maxSum = Integer.MIN_VALUE;
for (int right = 0; right < arr.length; right++) {
    sum += arr[right];
    if (right - left + 1 == k) { // 窗口大小达到k
        maxSum = Math.max(maxSum, sum);
        sum -= arr[left++]; // 滑动窗口
    }
}
模板:可变窗口大小(含哈希表)
java 复制代码
Map<Character, Integer> window = new HashMap<>();
int left = 0, maxLen = 0;
for (int right = 0; right < s.length(); right++) {
    char c = s.charAt(right);
    window.put(c, window.getOrDefault(c, 0) + 1);
    
    while (window.get(c) > 1) { // 收缩条件
        char d = s.charAt(left++);
        window.put(d, window.get(d) - 1);
    }
    
    maxLen = Math.max(maxLen, right - left + 1);
}

适用场景 :无重复字符最长子串、最小覆盖子串
时间复杂度:O(n) --- 每个元素最多进出窗口一次


🔑 二、链表

2.1 基础操作模板

反转链表(迭代)
java 复制代码
public ListNode reverseList(ListNode head) {
    ListNode prev = null, curr = head;
    while (curr != null) {
        ListNode next = curr.next; // 保存下一节点
        curr.next = prev;          // 反转指针
        prev = curr;               // 移动prev
        curr = next;               // 移动curr
    }
    return prev;
}

时间复杂度 :O(n)
空间复杂度:O(1)

反转链表(递归)
java 复制代码
public ListNode reverseList(ListNode head) {
    if (head == null || head.next == null) return head;
    ListNode newHead = reverseList(head.next);
    head.next.next = head; // 反转当前节点
    head.next = null;      // 避免环
    return newHead;
}

2.2 快慢指针高级应用

检测环(Floyd判圈算法)
java 复制代码
public boolean hasCycle(ListNode head) {
    if (head == null || head.next == null) return false;
    ListNode slow = head, fast = head;
    while (fast != null && fast.next != null) {
        slow = slow.next;
        fast = fast.next.next;
        if (slow == fast) return true; // 相遇即有环
    }
    return false;
}
寻找环入口
java 复制代码
public ListNode detectCycle(ListNode head) {
    ListNode slow = head, fast = head;
    while (fast != null && fast.next != null) {
        slow = slow.next;
        fast = fast.next.next;
        if (slow == fast) { // 相遇
            slow = head;    // 慢指针回到起点
            while (slow != fast) {
                slow = slow.next;
                fast = fast.next;
            }
            return slow; // 环入口
        }
    }
    return null;
}

数学原理 :设环外长度a,环内相遇点距入口b,环长c。相遇时:
2(a+b) = a + b + nca = (n-1)c + (c-b)

即从起点和相遇点同时走,必在入口相遇


🔑 三、栈与队列

3.1 单调栈(Monotonic Stack)

模板:寻找右侧第一个更大元素
java 复制代码
public int[] nextGreaterElement(int[] nums) {
    int[] result = new int[nums.length];
    Arrays.fill(result, -1);
    Deque<Integer> stack = new ArrayDeque<>(); // 存储索引
    
    for (int i = 0; i < nums.length; i++) {
        while (!stack.isEmpty() && nums[stack.peek()] < nums[i]) {
            int idx = stack.pop();
            result[idx] = nums[i];
        }
        stack.push(i);
    }
    return result;
}

适用场景 :柱状图最大矩形、每日温度
时间复杂度:O(n) --- 每个元素入栈出栈各一次


3.2 双端队列实现滑动窗口最大值

java 复制代码
public int[] maxSlidingWindow(int[] nums, int k) {
    if (nums == null || k <= 0) return new int[0];
    int[] result = new int[nums.length - k + 1];
    Deque<Integer> deque = new ArrayDeque<>(); // 存储索引,队首为最大值索引
    
    for (int i = 0; i < nums.length; i++) {
        // 移除队首过期元素
        if (!deque.isEmpty() && deque.peekFirst() < i - k + 1) {
            deque.pollFirst();
        }
        
        // 维护单调递减队列:移除队尾小于当前元素的索引
        while (!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) {
            deque.pollLast();
        }
        
        deque.offerLast(i);
        
        // 窗口形成后记录结果
        if (i >= k - 1) {
            result[i - k + 1] = nums[deque.peekFirst()];
        }
    }
    return result;
}

时间复杂度 :O(n)
空间复杂度:O(k)


🔑 四、二叉树

4.1 遍历模板

前序遍历(迭代)
java 复制代码
public List<Integer> preorderTraversal(TreeNode root) {
    List<Integer> result = new ArrayList<>();
    if (root == null) return result;
    
    Deque<TreeNode> stack = new ArrayDeque<>();
    stack.push(root);
    
    while (!stack.isEmpty()) {
        TreeNode node = stack.pop();
        result.add(node.val);
        if (node.right != null) stack.push(node.right); // 右先入栈
        if (node.left != null) stack.push(node.left);   // 左后入栈
    }
    return result;
}
中序遍历(迭代)
java 复制代码
public List<Integer> inorderTraversal(TreeNode root) {
    List<Integer> result = new ArrayList<>();
    Deque<TreeNode> stack = new ArrayDeque<>();
    TreeNode curr = root;
    
    while (curr != null || !stack.isEmpty()) {
        while (curr != null) {
            stack.push(curr);
            curr = curr.left; // 一路向左
        }
        curr = stack.pop();
        result.add(curr.val);
        curr = curr.right; // 转向右子树
    }
    return result;
}

4.2 二叉搜索树(BST)验证

java 复制代码
public boolean isValidBST(TreeNode root) {
    return validate(root, Long.MIN_VALUE, Long.MAX_VALUE);
}

private boolean validate(TreeNode node, long min, long max) {
    if (node == null) return true;
    if (node.val <= min || node.val >= max) return false;
    return validate(node.left, min, node.val) && 
           validate(node.right, node.val, max);
}

关键点 :不能仅比较父子节点,需传递上下界约束
时间复杂度 :O(n)
空间复杂度:O(h),h为树高


🔑 五、哈希表

5.1 LRU 缓存实现

java 复制代码
class LRUCache {
    private final int capacity;
    private final Map<Integer, Node> cache;
    private final Node head, tail; // 双向链表哑节点
    
    public LRUCache(int capacity) {
        this.capacity = capacity;
        cache = new HashMap<>();
        head = new Node(0, 0);
        tail = new Node(0, 0);
        head.next = tail;
        tail.prev = head;
    }
    
    public int get(int key) {
        if (!cache.containsKey(key)) return -1;
        Node node = cache.get(key);
        remove(node);
        add(node);
        return node.value;
    }
    
    public void put(int key, int value) {
        if (cache.containsKey(key)) {
            remove(cache.get(key));
        } else if (cache.size() >= capacity) {
            cache.remove(head.next.key);
            remove(head.next);
        }
        add(new Node(key, value));
    }
    
    private void add(Node node) {
        Node prev = tail.prev;
        prev.next = node;
        node.prev = prev;
        node.next = tail;
        tail.prev = node;
        cache.put(node.key, node);
    }
    
    private void remove(Node node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
        cache.remove(node.key);
    }
    
    static class Node {
        int key, value;
        Node prev, next;
        Node(int k, int v) { key = k; value = v; }
    }
}

时间复杂度 :get/put 均为 O(1)
空间复杂度:O(capacity)


🔑 六、堆与优先队列

6.1 Top K 问题模板

求前K大元素(小顶堆)
java 复制代码
public int[] topKFrequent(int[] nums, int k) {
    // 1. 统计频率
    Map<Integer, Integer> freq = new HashMap<>();
    for (int num : nums) freq.put(num, freq.getOrDefault(num, 0) + 1);
    
    // 2. 小顶堆维护Top K
    PriorityQueue<Map.Entry<Integer, Integer>> heap = 
        new PriorityQueue<>((a, b) -> a.getValue() - b.getValue());
    
    for (Map.Entry<Integer, Integer> entry : freq.entrySet()) {
        heap.offer(entry);
        if (heap.size() > k) heap.poll(); // 移除最小元素
    }
    
    // 3. 提取结果
    int[] result = new int[k];
    int i = 0;
    while (!heap.isEmpty()) result[i++] = heap.poll().getKey();
    return result;
}

时间复杂度 :O(n log k)
空间复杂度:O(n)


🔑 七、动态规划

7.1 背包问题模板

0-1背包(二维DP)
java 复制代码
public int knapsack(int[] weights, int[] values, int capacity) {
    int n = weights.length;
    int[][] dp = new int[n + 1][capacity + 1];
    
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= capacity; j++) {
            dp[i][j] = dp[i - 1][j]; // 不选第i个物品
            if (j >= weights[i - 1]) {
                dp[i][j] = Math.max(
                    dp[i][j],
                    dp[i - 1][j - weights[i - 1]] + values[i - 1] // 选第i个物品
                );
            }
        }
    }
    return dp[n][capacity];
}
0-1背包(空间优化:一维DP)
java 复制代码
public int knapsackOptimized(int[] weights, int[] values, int capacity) {
    int[] dp = new int[capacity + 1];
    for (int i = 0; i < weights.length; i++) {
        // 逆序遍历防止重复选择
        for (int j = capacity; j >= weights[i]; j--) {
            dp[j] = Math.max(dp[j], dp[j - weights[i]] + values[i]);
        }
    }
    return dp[capacity];
}

关键点:一维DP必须逆序遍历,避免物品被重复选择


7.2 股票买卖问题状态机

通用模板(含冷冻期)
java 复制代码
public int maxProfit(int[] prices) {
    int n = prices.length;
    if (n == 0) return 0;
    
    // dp[i][0]: 持有股票
    // dp[i][1]: 不持有(冷冻期)
    // dp[i][2]: 不持有(非冷冻期)
    int[][] dp = new int[n][3];
    
    dp[0][0] = -prices[0];
    dp[0][1] = 0;
    dp[0][2] = 0;
    
    for (int i = 1; i < n; i++) {
        dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][2] - prices[i]);
        dp[i][1] = dp[i - 1][0] + prices[i];
        dp[i][2] = Math.max(dp[i - 1][1], dp[i - 1][2]);
    }
    
    return Math.max(dp[n - 1][1], dp[n - 1][2]);
}

状态转移

  • 持有 = max(前一天持有, 前一天非冷冻期买入)
  • 冷冻期 = 前一天持有并卖出
  • 非冷冻期 = max(前一天冷冻期, 前一天非冷冻期)

🔑 八、图算法

8.1 BFS最短路径(无权图)

java 复制代码
public int shortestPath(int[][] graph, int start, int target) {
    if (start == target) return 0;
    
    Queue<Integer> queue = new LinkedList<>();
    Set<Integer> visited = new HashSet<>();
    queue.offer(start);
    visited.add(start);
    int steps = 0;
    
    while (!queue.isEmpty()) {
        int size = queue.size();
        steps++;
        for (int i = 0; i < size; i++) {
            int node = queue.poll();
            for (int neighbor : graph[node]) {
                if (neighbor == target) return steps;
                if (!visited.contains(neighbor)) {
                    visited.add(neighbor);
                    queue.offer(neighbor);
                }
            }
        }
    }
    return -1; // 不可达
}

8.2 DFS回溯模板

java 复制代码
public List<List<Integer>> subsets(int[] nums) {
    List<List<Integer>> result = new ArrayList<>();
    backtrack(nums, 0, new ArrayList<>(), result);
    return result;
}

private void backtrack(int[] nums, int start, List<Integer> path, 
                      List<List<Integer>> result) {
    result.add(new ArrayList<>(path)); // 每个节点都是解
    
    for (int i = start; i < nums.length; i++) {
        path.add(nums[i]);          // 做选择
        backtrack(nums, i + 1, path, result); // 递归
        path.remove(path.size() - 1); // 撤销选择
    }
}

关键点

  • path 传递引用需深拷贝加入结果集
  • start 参数避免重复选择(组合问题)
  • 排列问题需用 visited 数组标记

📊 复杂度速查表

数据结构/算法 时间复杂度(平均) 空间复杂度 适用场景
数组访问 O(1) O(1) 随机访问
链表遍历 O(n) O(1) 顺序访问、频繁插入删除
哈希表 O(1) O(n) 快速查找、去重
二叉搜索树 O(log n) O(n) 有序数据、范围查询
O(log n)插入/删除 O(1)查最值 O(n) Top K、优先队列
快排 O(n log n) O(log n) 通用排序
归并排序 O(n log n) O(n) 稳定排序、链表排序
BFS O(V+E) O(V) 最短路径(无权图)
DFS O(V+E) O(V) 连通性、回溯
动态规划 O(n²)~O(n) O(n²)~O(n) 最优子结构问题

⚠️ 高频边界陷阱清单

问题类型 边界条件 检查点
数组 空数组、单元素 `if (arr == null
二分查找 溢出、死循环 mid = left + (right - left) / 2 while (left <= right) vs while (left < right)
链表 空链表、单节点 `if (head == null
递归 栈溢出 深度>1000考虑迭代,尾递归优化
整数运算 溢出 (a + b) / 2a + (b - a) / 2 乘法前转 long
字符串 空串、单字符 `if (s == null
树遍历 空树 if (root == null) return ...
DP初始化 无效状态标记 Integer.MAX_VALUE / 2 避免加法溢出

🚀 面试编码 Checklist

开始编码前

  • 明确输入输出类型及范围
  • 询问边界条件处理方式(空值/负数/溢出)
  • 口头描述1-2种解法并分析复杂度
  • 确认最优解法后再编码

编码过程中

  • 变量命名清晰(避免a/b/c)
  • 关键步骤添加简短注释
  • 先实现主干逻辑,再处理边界
  • 每写5行代码自测一个小用例

编码完成后

  • 用简单用例走查代码(含边界)
  • 明确说明时间/空间复杂度
  • 主动提出可能的优化方向
  • 询问面试官是否需要改进

:本文所有代码模板均经过 LeetCode 核心题验证,可直接用于面试实战。建议针对每类题型手写3遍以上形成肌肉记忆。
更新日期:2026年2月14日

相关推荐
今儿敲了吗1 小时前
18| 差分数组
c++·笔记·学习·算法
学Linux的语莫1 小时前
skills的使用
java·数据库·python
Bear on Toilet1 小时前
BFS_FloodFill_46 . 腐烂的橘子问题
数据结构·c++·算法·leetcode·宽度优先
大模型玩家七七1 小时前
关系记忆不是越完整越好:chunk size 的隐性代价
java·前端·数据库·人工智能·深度学习·算法·oracle
样例过了就是过了1 小时前
LeetCode热题100 找到字符串中所有字母异位词
算法·leetcode
DevilSeagull1 小时前
C语言: C语言内存函数详解
c语言·开发语言·算法
搞科研的小刘选手2 小时前
【人工智能专题】2026年人工智能与生成式设计国际学术会议(ICAIGD 2026)
人工智能·算法·aigc·生成式ai·学术会议·计算机工程·生成式设计
stripe-python2 小时前
十二重铲雪法(上)
c++·算法
一 乐2 小时前
林业资源管理|基于java + vue林业资源管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·林业资源管理系统