一、先梳理常用算法分类(按高频排序)
以下是编程中最核心、最常考的算法,覆盖 90% 以上的基础题:
- 双指针法
- 动态规划
- 深度优先搜索(DFS)/ 广度优先搜索(BFS)
- 二分查找
- 哈希表(散列表)
- 并查集(Union-Find)
- 滑动窗口
二、逐个拆解:核心思路 + 应用场景 + 例子
1. 双指针法
核心思路
用两个指针(变量)在数组 / 链表上移动,一个快一个慢,或一个左一个右,通过指针的相对移动缩小处理范围,把 O (n²) 的时间复杂度降到 O (n)。
应用场景
- 数组 / 链表的遍历(比如找两数之和、反转字符串);
- 有序数组去重、合并两个有序数组;
- 链表的快慢指针(找环、找中间节点)。
简单例子(反转字符串)
// 输入:["h","e","l","l","o"] → 输出:["o","l","l","e","h"]
public void reverseString(char[] s) {
int left = 0; // 左指针从头部开始
int right = s.length - 1; // 右指针从尾部开始
while (left < right) {
// 交换左右指针的元素
char temp = s[left];
s[left] = s[right];
s[right] = temp;
left++; // 左指针右移
right--; // 右指针左移
}
}
2. 动态规划(DP)
核心思路
“大事化小,小事化了”—— 把复杂问题拆成重叠的子问题,记录子问题的解(存在 dp 数组里),避免重复计算,最终推导全局最优解。核心步骤:定义 dp 数组含义 → 找状态转移方程 → 确定初始条件 → 计算结果。
应用场景
- 最值问题(比如最长递增子序列、最小路径和);
- 计数问题(比如不同路径数);
- 背包问题(01 背包、完全背包)。
简单例子(斐波那契数列)
// 求第n个斐波那契数(dp[i] = dp[i-1] + dp[i-2])
public int fib(int n) {
if (n <= 1) return n;
int[] dp = new int[n+1];
dp[0] = 0; // 初始条件
dp[1] = 1; // 初始条件
for (int i = 2; i <= n; i++) {
dp[i] = dp[i-1] + dp[i-2]; // 状态转移方程
}
return dp[n];
}
3. 深度优先搜索(DFS)/ 广度优先搜索(BFS)
核心思路
- DFS:“一条路走到黑,走不通就回头”(递归 / 栈实现),适合找所有解、遍历树 / 图;
- BFS:“层层递进,先近后远”(队列实现),适合找最短路径、层级遍历。
应用场景
- DFS:子集、组合、全排列(回溯本质是 DFS 的一种)、树的前 / 中 / 后序遍历;
- BFS:二叉树的层序遍历、迷宫最短路径、朋友圈问题。
简单例子(BFS 遍历二叉树)
// 层序遍历二叉树:从上到下,一层一层输出节点值
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
if (root == null) return result;
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); // 右孩子入队
}
result.add(level);
}
return result;
}
4. 二分查找
核心思路
针对有序数组,每次取中间值和目标值比较,缩小一半查找范围,时间复杂度 O (logn),比遍历快得多。核心条件:左边界≤右边界,每次更新左 / 右边界。
应用场景
- 有序数组找目标值、找目标值的第一个 / 最后一个位置;
- 找峰值、平方根、旋转有序数组的最小值。
简单例子(找目标值)
// 有序数组nums中找target的下标,找不到返回-1
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2; // 避免溢出
if (nums[mid] == target) {
return mid; // 找到目标值
} else if (nums[mid] < target) {
left = mid + 1; // 目标值在右半区
} else {
right = mid - 1; // 目标值在左半区
}
}
return -1; // 没找到
}
5. 哈希表(散列表)
核心思路
通过 “哈希函数” 把键映射到对应位置,实现O (1) 时间的增删改查,核心是解决哈希冲突(Java 的 HashMap 用链表 + 红黑树解决)。
应用场景
- 快速查找(比如两数之和、统计元素出现次数);
- 去重、映射(比如字符异位词、罗马数字转整数)。
简单例子(两数之和)
// 找数组中两个数的下标,和为target
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (map.containsKey(complement)) {
return new int[]{map.get(complement), i};
}
map.put(nums[i], i); // 存数值和下标
}
return new int[0];
}
6. 并查集(Union-Find)
核心思路
处理 “动态连通性” 问题,比如判断两个元素是否在同一个集合、合并两个集合,核心操作是 “查找(找根节点)” 和 “合并(合并两个集合)”。
应用场景
- 朋友圈问题、岛屿数量;
- 图的连通分量、最小生成树(Kruskal 算法)。
简单例子(初始化 + 查找 + 合并)
class UnionFind {
private int[] parent; // 父节点数组
public UnionFind(int n) {
parent = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i; // 初始时,每个元素的父节点是自己
}
}
// 查找根节点(路径压缩,优化效率)
public int find(int x) {
if (parent[x] != x) {
parent[x] = find(parent[x]); // 路径压缩
}
return parent[x];
}
// 合并两个集合
public void union(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
parent[rootY] = rootX;
}
}
}
7. 滑动窗口
核心思路
用一个 “窗口”(左、右指针)在数组 / 字符串上滑动,动态维护窗口内的元素,把 O (n²) 降到 O (n),适合处理子数组 / 子字符串问题。
应用场景
- 最长无重复子串、最小覆盖子串;
- 子数组的最大和、找所有字母异位词。
简单例子(最长无重复子串)
// 找字符串中最长无重复字符的子串长度
public int lengthOfLongestSubstring(String s) {
Set<Character> set = new HashSet<>();
int left = 0; // 窗口左边界
int maxLen = 0;
for (int right = 0; right < s.length(); right++) {
// 如果窗口内有重复字符,左指针右移,直到无重复
while (set.contains(s.charAt(right))) {
set.remove(s.charAt(left));
left++;
}
set.add(s.charAt(right)); // 右指针右移,加入字符
maxLen = Math.max(maxLen, right - left + 1); // 更新最大长度
}
return maxLen;
}
总结
- 优先掌握:双指针、哈希表、二分查找(入门易、应用广);
- 重点突破:动态规划、DFS/BFS(稍难,但占面试题核心);
- 补充学习:并查集、滑动窗口(解决特定场景问题);
- 算法选择技巧:
- 有序数组→二分查找;
- 最值 / 子问题→动态规划;
- 数组 / 字符串遍历优化→双指针 / 滑动窗口;
- 树 / 图遍历→DFS/BFS;
- 快速查找 / 统计→哈希表。
1265

被折叠的 条评论
为什么被折叠?



