概述
算法思维是解决编程问题的核心能力。它不仅仅是记住某个具体算法的实现,更重要的是理解问题的本质,选择合适的解决策略,并高效地实现。
- 举一反三 — 掌握一种思维,解决一类问题
- 快速定位 — 面对新问题时迅速找到解决方向
- 优化意识 — 从暴力解法逐步优化到最优解
- 面试必备 — 技术面试中考察的核心能力
🎯 算法思维的本质
十大算法思维详解
以下是编程中最常用的十种算法思维,每种思维都配有核心概念、适用场景和典型例题。
递归思维
将大规模问题转化为相同结构的小规模问题,通过解决子问题来解决原问题。 核心是找到递推关系和终止条件。
递归函数 = 终止条件 + 递归调用 + 结果合并
- 问题可以分解为相同结构的子问题
- 树的遍历(前序、中序、后序)
- 分治算法的基础
- 动态规划的状态转移
- 斐波那契数列
- 约瑟夫环问题
- 汉诺塔问题
- 二叉树的最大深度
分治思维
分而治之,将复杂问题分解为多个独立的子问题,分别求解后合并结果。 是递归思维的典型应用。
分解 → 解决 → 合并
- 问题可以分解为独立的子问题
- 子问题的解可以合并为原问题的解
- 子问题规模足够小时可直接求解
- 归并排序
- 快速排序
- 快速幂
- 求数组的逆序对
贪心思维
每一步都做出局部最优选择,期望最终得到全局最优解。 关键是证明贪心策略的正确性。
局部最优 → 全局最优
- 问题具有贪心选择性质
- 局部最优能推导全局最优
- 区间问题、调度问题
- 活动选择问题
- 霍夫曼编码
- 最小生成树(Prim、Kruskal)
- 跳跃游戏
动态规划
将问题分解为重叠子问题,保存子问题的解避免重复计算。 核心是状态定义和状态转移方程。
定义状态 → 状态转移 → 初始条件 → 计算顺序
- 问题具有最优子结构
- 存在重叠子问题
- 计数问题、最值问题、存在性问题
- 背包问题
- 最长公共子序列
- 编辑距离
- 零钱兑换
回溯思维
试错法,逐步构建解决方案,发现当前路径不可行时回退到上一步重新选择。 本质是 DFS 的应用。
做选择 → 递归 → 撤销选择
- 组合问题、排列问题
- 子集问题、分割问题
- N 皇后、数独等约束满足问题
- 全排列
- 组合总和
- N 皇后
- 括号生成
滑动窗口
维护一个窗口在数组/字符串上滑动,通过扩张和收缩窗口来找到满足条件的子数组/子串。 可将 O(n²) 优化到 O(n)。
右边界扩张 → 满足条件 → 左边界收缩
- 连续子数组/子串问题
- 固定长度窗口或可变长度窗口
- 最值问题、计数问题
- 无重复字符的最长子串
- 最小覆盖子串
- 长度最小的子数组
- 字符串的排列
双指针
使用两个指针在数组上移动,可以是相向而行、同向移动或快慢指针。 常用于优化暴力解法。
左右指针 | 快慢指针 | 分离双指针
- 有序数组的两数之和
- 链表问题(环检测、中点)
- 原地修改数组
- 合并两个有序数组
- 两数之和 II
- 接雨水
- 移动零
- 链表中点
二分查找
在有序或具有单调性的数据结构中,每次排除一半的搜索空间。 时间复杂度 O(log n)。
确定边界 | 避免死循环 | 处理重复
- 有序数组查找
- 查找边界(第一个/最后一个)
- 答案具有单调性的最值问题
- 旋转数组查找
- 二分查找
- 搜索旋转排序数组
- 寻找峰值
- 爱吃香蕉的珂珂
DFS & BFS
DFS(深度优先):一条路走到黑,适合遍历所有可能。
BFS(广度优先):层层推进,适合找最短路径。
DFS → 栈(递归) | BFS → 队列
- 图的遍历和搜索
- 树的遍历
- 连通性问题
- 最短路径(BFS)
- 岛屿数量
- 单词接龙
- 二叉树层序遍历
- 课程表
马拉车算法
在 O(n) 时间内找到字符串的最长回文子串。 利用回文的对称性避免重复计算。
预处理插入# | 利用对称性 | 维护最右边界
- 最长回文子串
- 回文相关计数问题
- 字符串对称性问题
- 最长回文子串
- 回文子串计数
- 最短回文串
KMP 算法
高效的字符串模式匹配算法,时间复杂度 O(m+n)。 核心是构建next 数组(部分匹配表),避免回溯。
利用已匹配信息 | 构建 next 数组 | 主串不回溯
- 字符串模式匹配
- 查找子串首次出现位置
- 重复子串判断
- 实现 strStr()
- 重复的子字符串
- 最短回文串
并查集
高效处理不相交集合的合并与查询问题。 支持两种操作:Union(合并)、Find(查询代表元)。
路径压缩 | 按秩合并
- 连通性问题
- 动态连通性
- 最小生成树(Kruskal)
- 判断图中是否有环
- 岛屿数量
- 冗余连接
- 被围绕的区域
- 朋友圈
算法思维对比框架
理解不同算法思维之间的区别和联系,帮助你在面对问题时快速选择合适的策略。
⚖️ 核心维度对比
| 算法思维 | 时间复杂度 | 空间复杂度 | 核心特点 | 难度 |
|---|---|---|---|---|
| 递归 | 视问题而定 | O(n) 栈空间 | 代码简洁,数学优雅 | ⭐⭐ |
| 分治 | O(n log n) | O(log n) | 分解 - 解决 - 合并 | ⭐⭐⭐ |
| 贪心 | O(n log n) 或 O(n) | O(1) | 局部最优推导全局最优 | ⭐⭐⭐ |
| 动态规划 | O(n²) 或 O(n³) | O(n) 可优化 | 重叠子问题,最优子结构 | ⭐⭐⭐⭐ |
| 回溯 | 指数级 | O(n) | 试错,可剪枝优化 | ⭐⭐⭐ |
| 滑动窗口 | O(n) | O(1) 或 O(k) | 维护窗口,避免重复 | ⭐⭐⭐ |
| 双指针 | O(n) | O(1) | 空间优化,原地操作 | ⭐⭐ |
| 二分查找 | O(log n) | O(1) | 每次排除一半 | ⭐⭐ |
算法选择决策树
面对一个新问题时,按照以下决策树快速定位合适的算法思维。
重叠子问题?} B -->|查找/定位 | D{数据是否有序?} B -->|排列/组合/方案 | E[🔙 回溯算法] B -->|连续子数组/子串 | F[🪟 滑动窗口] B -->|连通性/合并 | G[🔗 并查集] B -->|字符串匹配 | H{精确匹配?} C -->|是 | I[📊 动态规划] C -->|否 | J{能否
局部最优?} J -->|能 | K[🎯 贪心算法] J -->|不能 | L[📐 分治法] D -->|是 | M[🎯 二分查找] D -->|否 | N[👆 双指针
或哈希表] H -->|是 | O[🔍 KMP 算法] H -->|回文问题 | P[🔤 马拉车] style A fill:#667eea,color:#fff style I fill:#e53e3e,color:#fff style K fill:#ed8936,color:#fff style L fill:#48bb78,color:#fff style M fill:#e53e3e,color:#fff style E fill:#805ad5,color:#fff style F fill:#319795,color:#fff style G fill:#319795,color:#fff style O fill:#d69e2e,color:#fff style P fill:#805ad5,color:#fff style N fill:#d69e2e,color:#fff
推荐学习路径
按照以下顺序系统学习算法思维,循序渐进提升解题能力。
掌握递归三要素
快速幂
快慢指针
可变窗口
树的遍历
剪枝优化
贪心证明
背包问题
状态压缩
- 理解优先 — 先理解思维本质,再记忆模板
- 刻意练习 — 每种思维至少练习 5-10 道典型题目
- 总结归纳 — 建立自己的解题模板和错题本
- 举一反三 — 同一题目尝试多种解法