
在计算机科学与工程领域,算法是解决问题的核心工具。无论是数据处理、人工智能、图形渲染还是网络通信,算法都扮演着至关重要的角色。掌握算法不仅是提升编程能力的关键,更是进入大厂、参与高难度项目和构建高质量软件系统的基础。
学习路径规划
目标:
学习内容:
主题 | 学习内容 | 时间复杂度案例 | STL容器对应实现 |
|---|---|---|---|
数据结构 | 数组 | O(1)随机访问 | std::vector |
链表 | O(n)插入/删除 | std::list/std::forward_list | |
栈 | O(1)压栈/弹栈 | std::stack | |
队列 | O(1)队尾插入/队首删除 | std::queue | |
哈希表 | O(1)平均查询 | std::unordered_map | |
时间复杂度 | O(1)常数时间 | 数组索引访问 | |
O(log n)对数时间 | 二分查找 | std::map/std::set | |
O(n)线性时间 | 线性遍历 | ||
O(n²)平方时间 | 嵌套循环 | ||
O(n log n)线性对数时间 | 快速排序 | std::priority_queue |
关键说明
std::deque支持O(1)随机访问,兼具队列和栈的特性std::map和std::set基于红黑树实现,操作复杂度为O(log n)std::unordered_map哈希表实现,平均O(1)但最差O(n)vector map:
#include <iostream>
#include <vector>
#include <map>
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};
std::map<std::string, int> scores;
scores["Alice"] = 90;
scores["Bob"] = 85;
for (int num : nums) {
std::cout << num << " ";
}
std::cout << std::endl;
for (const auto& pair : scores) {
std::cout << pair.first << ": " << pair.second << std::endl;
}
return 0;
}目标:
推荐学习内容:
主题 | 算法/问题 | 具体内容 |
|---|---|---|
排序算法 | 冒泡排序 | 相邻元素交换,逐步将最大值移至末尾 |
插入排序 | 构建有序序列,未排序元素插入适当位置 | |
选择排序 | 每次选择最小元素与未排序部分首位交换 | |
快速排序 | 分治思想,基准值分区递归排序 | |
归并排序 | 分治法,子序列排序后合并 | |
查找算法 | 顺序查找 | 逐个遍历数据直到找到目标 |
二分查找 | 有序数据中折半缩小搜索范围 | |
递归与分治 | 斐波那契数列 | 递归定义F(n)=F(n-1)+F(n-2) |
汉诺塔 | 递归移动圆盘至目标柱 | |
归并排序 | 分治法的排序应用 | |
快速排序 | 分治法的排序应用 | |
贪心算法 | 活动选择 | 选择不冲突的最大活动集合 |
硬币找零 | 优先使用大面额硬币 | |
区间调度 | 选择结束最早的区间以最大化数量 | |
动态规划 | 背包问题 | 0-1背包或完全背包的状态转移方程 |
最长公共子序列 | 二维DP表记录匹配状态 | |
斐波那契数列优化 | 记忆化搜索或迭代法避免重复计算 |
如:快速排序实现:
#include <iostream>
#include <vector>
void quickSort(std::vector<int>& arr, int left, int right) {
if (left >= right) return;
int pivot = arr[(left + right) / 2];
int i = left, j = right;
while (i <= j) {
while (arr[i] < pivot) i++;
while (arr[j] > pivot) j--;
if (i <= j) {
std::swap(arr[i], arr[j]);
i++;
j--;
}
}
quickSort(arr, left, j);
quickSort(arr, i, right);
}
int main() {
std::vector<int> nums = {5, 3, 8, 6, 7, 2};
quickSort(nums, 0, nums.size() - 1);
for (int num : nums) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}目标:
学习内容:
图论
算法/概念 | 说明 |
|---|---|
DFS/BFS | 图的深度优先搜索与广度优先搜索 |
Dijkstra | 单源最短路径算法(非负权图) |
Floyd | 多源最短路径算法(动态规划实现) |
Kruskal/Prim | 最小生成树算法(贪心思想) |
字符串匹配
算法/概念 | 说明 |
|---|---|
KMP | 基于部分匹配表的高效串匹配算法 |
Trie | 前缀树结构,用于多模式存储与查询 |
AC自动机 | 多模式匹配的Trie树优化版本 |
高级动态规划
算法/概念 | 说明 |
|---|---|
状态压缩DP | 用二进制位表示状态以减少空间复杂度 |
区间DP | 以区间为阶段的动态规划(如石子合并) |
斜率优化DP | 利用凸包性质优化转移方程 |
高级数据结构
算法/概念 | 说明 |
|---|---|
并查集 | 高效处理集合合并与查询操作 |
线段树 | 支持区间查询与更新的二叉树结构 |
树状数组 | 高效实现前缀操作的二进制索引树 |
堆优化 | 优先队列在算法中的应用(如Dijkstra) |
算法名称 | 时间复杂度 | 空间复杂度 | 是否稳定 | 适用场景 |
|---|---|---|---|---|
冒泡排序 | O(n²) | O(1) | 是 | 小规模或教学 |
插入排序 | O(n²) | O(1) | 是 | 几乎有序数据 |
快速排序 | O(n log n) | O(log n) | 否 | 通用排序 |
归并排序 | O(n log n) | O(n) | 是 | 大数据排序 |
堆排序 | O(n log n) | O(1) | 否 | Top K 问题 |
算法名称 | 时间复杂度 | 说明 |
|---|---|---|
顺序查找 | O(n) | 适用于无序数据 |
二分查找 | O(log n) | 仅适用于有序数据 |
散列查找 | O(1) | 需处理哈希冲突问题 |
经典问题:
如 最长公共子序列(LCS)
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int lcs(string s1, string s2) {
int m = s1.size(), n = s2.size();
vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (s1[i - 1] == s2[j - 1])
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
}
return dp[m][n];
}
int main() {
string s1 = "abcde", s2 = "ace";
cout << "LCS Length: " << lcs(s1, s2) << endl;
return 0;
}算法 | 应用场景 |
|---|---|
BFS | 最短路径(无权图) |
DFS | 连通性检测、拓扑排序 |
Dijkstra | 单源最短路径(有权图) |
Floyd-Warshall | 所有点对最短路径 |
Kruskal/Prim | 最小生成树 |
如 Dijkstra 最短路径算法:
#include <iostream>
#include <vector>
#include <queue>
#include <climits>
using namespace std;
typedef pair<int, int> pii;
void dijkstra(int start, vector<vector<pii>>& graph, vector<int>& dist) {
priority_queue<pii, vector<pii>, greater<pii>> pq;
dist[start] = 0;
pq.push({0, start});
while (!pq.empty()) {
int u = pq.top().second;
int d = pq.top().first;
pq.pop();
if (d > dist[u]) continue;
for (auto edge : graph[u]) {
int v = edge.first;
int weight = edge.second;
if (dist[v] > dist[u] + weight) {
dist[v] = dist[u] + weight;
pq.push({dist[v], v});
}
}
}
}
int main() {
int n = 5; // number of nodes
vector<vector<pii>> graph(n);
// Add edges
graph[0].push_back({1, 10});
graph[0].push_back({3, 5});
graph[1].push_back({2, 1});
graph[1].push_back({3, 2});
graph[2].push_back({4, 4});
graph[3].push_back({1, 3});
graph[3].push_back({4, 9});
graph[4].push_back({0, 7});
graph[4].push_back({2, 6});
vector<int> dist(n, INT_MAX);
dijkstra(0, graph, dist);
for (int i = 0; i < n; ++i) {
cout << "Distance from node 0 to node " << i << " is " << dist[i] << endl;
}
return 0;
}特点:
问题:
平台 | 特点 |
|---|---|
LeetCode | 高质量算法题库,面试常考 |
Codeforces | 比赛丰富,适合打比赛 |
AtCoder | 日本平台,题型新颖 |
牛客网 | 国内公司笔试题多 |
算法竞赛入门经典 | 紫书,适合系统学习 |
CLRS《算法导论》 | 理论扎实,适合深入研究 |
建议按如下分类进行刷题训练:
类别 | 推荐题号(LeetCode) |
|---|---|
数组 | 1、11、15、167 |
字符串 | 3、5、14、20 |
双指针 | 11、15、16、125 |
滑动窗口 | 3、76、239 |
堆 | 215、295、347 |
DFS/BFS | 102、104、200、547 |
动态规划 | 5、53、62、64、139、152 |
图论 | 207、210、743、785 |
阶段 | 每日目标 | 时间安排 |
|---|---|---|
初级 | 2~3道简单题 | 1小时 |
中级 | 1道中等+1道简单 | 1.5小时 |
高级 | 1道困难+1道中等 | 2小时 |
错误类型 | 表现形式 | 解决方案 |
|---|---|---|
边界条件 | 越界访问、死循环 | 使用 assert 或打印中间变量 |
初始化错误 | 结果始终为 0 或极大值 | 检查初始化逻辑 |
类型转换 | 溢出、精度丢失 | 使用 long long、double |
指针操作 | 内存泄漏、空指针 | 使用智能指针、注意 delete |
推荐书籍与网站
类加粗样式型 | 名称 | 说明 |
|---|---|---|
教材 | 《算法导论》 | 理论扎实,适合深入研究 |
教材 | 《算法竞赛入门经典》 | 系统学习,适合打基础 |
网站 | LeetCode | 高频面试题库 |
网站 | Codeforces | 比赛平台,锻炼思维 |
视频 | Bilibili 算法区 | 免费视频教程 |
社区 | Stack Overflow | 解决疑难问题 |
算法不是背出来的,是写出来的,持续练习,保持热情,算法之路必将越走越宽!