CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
数据结构与算法入门/课时/刷题模式
RawBlame
课时目录12 节

数据结构与算法入门

  1. 01语言与基础
  2. 02基础数据结构
  3. 03复杂度分析
  4. 04排序算法
  5. 05搜索算法
  6. 06树结构
  7. 07图算法
  8. 08高级结构
  9. 09经典技巧
  10. 10刷题模式
  11. 11练习平台
  12. 12综合练习

刷题模式

双指针、滑窗等。

30 分钟

刷题模式总结:常见题型与解题模板

这一课你将能做到

  1. 看到题目快速归类到「两数之和」「Top K」「区间合并」等模式
  2. 直接套用模板代码,减少思考成本
  3. 根据数据范围预判算法复杂度是否可行

为什么要学

刷题不是拼智商,是拼模式识别。95% 的中等题都是经典模式的变种。掌握 20 个核心模式,胜过做 200 道零散题目。

人话:就像学数学公式,遇到面积题就用 S=ab,遇到速度题就用 v=s/t。刷题也有公式。

先建立图像

题型 → 模式 → 模板 → 代码

两数之和 → 哈希表/双指针
Top K   → 堆/快排选择
区间合并 → 排序+贪心
树遍历  → DFS/BFS
最短路  → Dijkstra/BFS

跟着做

步骤 1:哈希表模式

import java.util.*;

public class Main {
    // 两数之和(无序数组)
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            int need = target - nums[i];
            if (map.containsKey(need)) {
                return new int[]{map.get(need), i};
            }
            map.put(nums[i], i);
        }
        return new int[]{-1, -1};
    }
    
    // 无重复最长子串
    public int lengthOfLongestSubstring(String s) {
        Map<Character, Integer> last = new HashMap<>();
        int left = 0, max = 0;
        for (int right = 0; right < s.length(); right++) {
            char c = s.charAt(right);
            if (last.containsKey(c) && last.get(c) >= left) {
                left = last.get(c) + 1;
            }
            last.put(c, right);
            max = Math.max(max, right - left + 1);
        }
        return max;
    }
    
    public static void main(String[] args) {
        Main m = new Main();
        int[] res = m.twoSum(new int[]{2,7,11,15}, 9);
        System.out.println(res[0] + ", " + res[1]);
    }
}

适用:查找、去重、统计频率。复杂度 O(n)。

步骤 2:Top K 模式

import java.util.*;

public class Main {
    // 第 K 大元素
    public int findKthLargest(int[] nums, int k) {
        PriorityQueue<Integer> heap = new PriorityQueue<>(); // 小顶堆
        for (int num : nums) {
            heap.offer(num);
            if (heap.size() > k) heap.poll();
        }
        return heap.peek();
    }
    
    // 前 K 高频
    public List<Integer> topKFrequent(int[] nums, int k) {
        Map<Integer, Integer> count = new HashMap<>();
        for (int num : nums) count.put(num, count.getOrDefault(num, 0) + 1);
        
        PriorityQueue<Map.Entry<Integer, Integer>> heap = new PriorityQueue<>(
            Comparator.comparingInt(Map.Entry::getValue)
        );
        for (Map.Entry<Integer, Integer> e : count.entrySet()) {
            heap.offer(e);
            if (heap.size() > k) heap.poll();
        }
        
        List<Integer> res = new ArrayList<>();
        while (!heap.isEmpty()) res.add(heap.poll().getKey());
        return res;
    }
    
    public static void main(String[] args) {
        Main m = new Main();
        System.out.println(m.findKthLargest(new int[]{3,2,1,5,6,4}, 2)); // 5
    }
}

适用:前 K 大/小、中位数。复杂度 O(n log k)。

步骤 3:区间合并模式

import java.util.*;

public class Main {
    public int[][] merge(int[][] intervals) {
        Arrays.sort(intervals, (a, b) -> a[0] - b[0]);
        List<int[]> res = new ArrayList<>();
        for (int[] interval : intervals) {
            if (res.isEmpty() || res.get(res.size() - 1)[1] < interval[0]) {
                res.add(interval);
            } else {
                res.get(res.size() - 1)[1] = Math.max(res.get(res.size() - 1)[1], interval[1]);
            }
        }
        return res.toArray(new int[0][]);
    }
    
    public static void main(String[] args) {
        Main m = new Main();
        int[][] res = m.merge(new int[][]{{1,3},{2,6},{8,10},{15,18}});
        for (int[] r : res) System.out.println(Arrays.toString(r)); // [1,6] [8,10] [15,18]
    }
}

适用:区间重叠、会议室安排、插入区间。复杂度 O(n log n)。

步骤 4:二叉树遍历模板

import java.util.*;

public class Main {
    // 前序遍历(根左右)
    public List<Integer> preorder(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        while (root != null || !stack.isEmpty()) {
            while (root != null) {
                res.add(root.val);
                stack.push(root);
                root = root.left;
            }
            root = stack.pop().right;
        }
        return res;
    }
    
    // 层序遍历(BFS)
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if (root == null) return res;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            int size = queue.size();
            List<Integer> level = new ArrayList<>();
            for (int i = 0; i < size; i++) {
                TreeNode node = queue.poll();
                level.add(node.val);
                if (node.left != null) queue.offer(node.left);
                if (node.right != null) queue.offer(node.right);
            }
            res.add(level);
        }
        return res;
    }
    
    public static void main(String[] args) {}
    
    static class TreeNode {
        int val;
        TreeNode left, right;
        TreeNode(int x) { val = x; }
    }
}

步骤 5:数据范围预判

n ≤ 20       → 枚举/回溯/状态压缩
n ≤ 100      → O(n³) 动态规划
n ≤ 1000     → O(n²) 双循环/DP
n ≤ 10^5     → O(n log n) 排序/二分/堆
n ≤ 10^6     → O(n) 线性扫描
n ≤ 10^9     → O(log n) 数学/二分

讲清楚要点

  1. 模式识别优先:看到「两个数的和」→ 哈希表;看到「前 K」→ 堆;看到「区间」→ 排序+贪心。
  2. 模板记忆:记住核心代码结构,细节现场推导。
  3. 复杂度预判:根据 n 的范围直接锁定可用算法,排除不可能的选项。
  4. 边界处理:空输入、单个元素、最大最小值是 WA 的三大来源。

你可能会懵的地方

  • 怎么知道这道题是什么模式? 看关键词。"和为 target"→哈希表;"前 K"→堆;"区间"→排序+贪心;"最短路径"→BFS/Dijkstra。

  • 模板背不下来怎么办? 不用背全部,记住核心结构。哈希表就是「遍历查补」;堆就是「入堆超量弹」;滑动窗口就是「右扩左缩」。

  • 一题多解怎么选? 看数据范围。n≤10^3 选 O(n²),n≤10^5 选 O(n log n)。空间换时间是常规策略。

  • 为什么写对了还 TLE? Java 常数大。检查 IO(BufferedReader),检查不必要的对象创建(StringBuilder 攒输出)。

  • 怎么提高模式识别速度? 按模式分类刷题,不要按顺序刷。每个模式集中做 10 道题,就能一眼认出。

错法对照

错法问题正解
用数组扫描代替哈希表O(n²) TLE空间换时间
Top K 直接排序O(n log n) 超时堆优化到 O(n log k)
区间不排序直接合并结果错误先按左端点排序
DFS 不处理边界栈溢出或结果错误加 null 判断和剪枝
无视数据范围选算法超时或内存超限先算 n 的范围再选算法

卡点急救

  1. 不知道什么模式:列举题目关键词,对照上面的模式表。还是不知道就试暴力,再优化。
  2. 模板套用出错:对比标准模板,逐行检查变量名和边界条件。
  3. 常数因子导致 TLE:用 BufferedReader 读入,StringBuilder 输出,避免频繁 new 对象。

面试常问

  • 刷题最有效的方法是什么? 按模式分类刷,每类 10 道。第一遍理解,第二遍默写,第三遍变形。

  • 如何判断算法复杂度是否可行? 代入 n 的值:10^5 时 O(n²)=10^10 必挂,O(n log n)=10^6 可以。

  • 面试官要求优化怎么办? 先给暴力解,说明复杂度;再分析瓶颈,提出优化方向;最后写最优解。

自测三问

  1. 看到「两个数的和」应该用什么模式?
  2. n=10^5 时哪些复杂度是可行的?
  3. 区间合并模式的核心步骤是什么?

小结一句话

刷题不是记忆,是模式识别;掌握 20 个核心模式,胜过做 200 道零散题目。

延伸

  • LeetCode 官方题解
  • 下一课:实战演练——综合题目拆解。
加载本节练习…
← 上一课经典技巧下一课 →练习平台