如何写出算法题?-算法思维
算法思维过程
能问出这个问题?你已经走在提升算法水平的核心路上了。
刷题本身只是手段,真正关键的就是「算法思维过程」。
下面总结给你一套可执行的“算法思维训练体系”,直接拿去用:
? 一、转变思维方式:从“找答案”转为“学过程”
✅ 错题是宝藏,做不出来没关系,核心是:
- 想清楚:我为什么会卡住?
- 是因为思路没拓展?不会拆分?不了解数据结构?对复杂度没概念?
? 建议: 每次遇到新题,至少逼自己想10分钟,用以下问题问自己:
1. 有没有最直接的暴力解?(不要怕,先写出来)
2. 会不会超时?大概什么复杂度?
3. 有没有能拆分成两个部分的结构?(分治、分组)
4. 有没有能用哈希表、双指针、前缀和、排序优化的地方?
5. 这题和我做过的哪道题像?能借鉴吗?
? 二、每学一种算法,都给自己留“刻意练习”任务
比如:
学到的算法 | 刻意练习方向 |
---|---|
哈希表 | 练「两数之和」、「四数之和」、「异或」、「字符统计」 |
双指针 | 练「有序数组去重」、「盛水最多的容器」、「三数之和」 |
前缀和、差分 | 练「区间和」、「二维前缀和」、「差分数组」 |
滑动窗口 | 练「最小子串覆盖」、「最长无重复子串」、「滑动最大值」 |
递归 & 回溯 | 练「全排列」、「组合」、「子集」、「N皇后」 |
二分 | 练「搜索区间」、「求平方根」、「最大最小问题」 |
? 核心在于:每种方法,找到 3-5 道有代表性的题目,死磕,做到:
- 看完题,第一反应就想起这招
- 练出手感
? 三、锻炼“建模”的能力
很多题目是文字游戏,关键在于“把问题抽象成熟悉的模型”:
题目场景 | 建模思路 |
---|---|
找满足条件的组合 | 转换成「nSum」模型 |
连续区间内最大/最小值 | 想到「前缀和」「单调队列」「滑动窗口」 |
涉及顺序的问题 | 想到「栈」「队列」「递归」 |
统计方案数 | 想「dp」有没有必要 |
树、图的遍历 | 立刻往「BFS」「DFS」靠 |
? 四、刷题顺序建议(重要)
先刷经典题,锻炼你对这些思维的掌控力:
1. 数组:两数之和、三数之和、盛水容器
2. 哈希表:有效的字母异位词、四数相加
3. 双指针:有序数组去重、最小覆盖子串
4. 栈/队列:有效括号、每日温度
5. 动态规划:爬楼梯、背包、最长子序列
6. 二分:搜索区间、旋转数组
7. 前缀和 & 差分:区间和,子数组和为K
8. 图:BFS、DFS模板题
? 五、写题解/反思(形成完整闭环)
✅ 你做一道题,试图给“未来的自己”写一份思路笔记:
1. 题目的核心是啥?本质模型?
2. 我一开始想到的暴力解法是什么?为什么不行?
3. 最终解法用了啥优化技巧?
4. 这个技巧能迁移到哪里?
? 比如:
- 这题让我学会了「哈希表统计组合次数」
- 类似的还有「两数之和」「三数之和」等问题
? 六、推荐工具/训练资源
类型 | 推荐 |
---|---|
刷题平台 | 力扣(LeetCode)、AcWing(有中文讲解) |
题单 | LeetCode Top 100、经典算法分类题单 |
书 | 《剑指 Offer》、《程序员代码面试指南》 |
视频 | 哔哩哔哩 左神、花花酱算法、代码随想录 |
社区 | 公众号「代码随想录」、力扣官方讨论区 |
✅ 总结:真正的算法高手都是这样炼成的
- 多问自己为什么:卡住时别马上看答案,先反思哪里想不到
- 多做题型归纳:一题多解,一题带一类
- 多总结核心模型:哈希表、前缀和、双指针……烂熟于心
- 形成完整闭环:做、想、总结、复盘,不断内化
示例
这就是学会「算法思维过程」的关键步骤。
借鉴题目 "4Sum II"(力扣:四数之和),很经典。接下来我带你走一遍“正常人做题的思路 + 试错 + 碰壁 + 优化”的完整过程。
? 第一步:最直接的暴力思路
【想法】
题目问 (i, j, k, l)
满足 A[i] + B[j] + C[k] + D[l] == 0
- i、j、k、l 都独立,可以四层循环,把所有可能列出来
- 每找到一组符合的就
count++
【代码雏形】
int count = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
for (int k = 0; k < N; k++) {
for (int l = 0; l < N; l++) {
if (A[i] + B[j] + C[k] + D[l] == 0) count++;
}
}
}
}
【试错点】
- 时间复杂度
O(N^4)
- N最大500 → 500⁴ = 6250亿次循环
- 明显超时!暴力直接死!
? 第二步:尝试优化——分组 + 预处理
【灵感来源】
- 想到:
A[i] + B[j] + C[k] + D[l] == 0
可以拆成两部分 (A[i] + B[j]) + (C[k] + D[l]) == 0
- 如果能先算出
A[i] + B[j]
所有可能,然后去查找-(C[k] + D[l])
,问题会简单很多!
【核心突破】
- 构建
unordered_map<int, int>
,key 是A[i] + B[j]
的和,value 是出现的次数(因为可能有重复) - 再枚举
C[k] + D[l]
,每算一个就看-(C[k] + D[l])
是否在 map 里
? 第三步:算算复杂度
A[i] + B[j]
枚举一遍:O(N^2)
C[k] + D[l]
再枚举一遍:O(N^2)
- 查询 map 是
O(1)
- 总复杂度
O(N^2) + O(N^2) = O(N^2)
,完美解决500的数据量!
? 第四步:模拟试错版本
假设:
A = [1, 2], B = [-2, -1], C = [-1, 2], D = [0, 2]
先处理 A + B
:
- 1 + (-2) = -1
- 1 + (-1) = 0
- 2 + (-2) = 0
- 2 + (-1) = 1
结果:
sumAB = {
-1: 1,
0: 2,
1: 1
}
再处理 C + D
并查 map:
- -1 + 0 = -1 → 看
1
是否在sumAB
- -1 + 2 = 1 → 看
-1
是否在sumAB
- 2 + 0 = 2 → 看
-2
是否在sumAB
- 2 + 2 = 4 → 看
-4
是否在sumAB
查到的部分:
- -1 在
sumAB
,有1个 → 计数 +1 - 1 在
sumAB
,有1个 → 计数 +1
最终答案:2
✍ 第五步:总结一般解题套路(非常重要)
阶段 | 做法 | 典型思路 |
---|---|---|
1. 暴力尝试 | 四层循环,发现复杂度炸了 | 暴力总是第一想法 |
2. 分组降维 | 发现可以 (A+B) (C+D) 分组 | 分组思想 |
3. 哈希优化 | 用 map 统计出现次数,反查匹配 | 空间换时间 |
4. 时间复杂度 | 优化到 O(N^2) | 可接受 |
5. 通用套路 | 多数求和问题可尝试「分组 + 哈希表」 | nSum问题 |
? 这题的本质
- 本质上是「四数之和等于0」的计数问题
- 通用解法:前一半枚举进哈希表,后一半直接查找匹配
- 扩展题目也能用类似思路做