学习算法最好的方法就是刷题了,上大学的时候刷过一些,最近开始转战 LeetCode。
让天下没有难学的算法
C语言免费动漫教程,和我一起打卡! 《光天化日学C语言》
入门级C语言真题汇总 《C语言入门100例》
几张动图学会一种数据结构 《画解数据结构》
组团学习,抱团生长 《算法入门指引》
竞赛选手金典图文教程 《夜深人静写算法》
千万不要用工作忙来找借口,时间挤一挤总是有的。
所以,无论你是 小学生,中学生,高中OIer,大学ACMer,职场人士,只要想开始,一切都不会太晚!
现在一些主流的大厂,在面试快结束的时候都会 奉上一道算法题,如果你敲不出来,可能你的 offer 年包就打了 七折,或者直接与 offer 失之交臂,都是有可能的(因为我自己也是万恶的面试官,看到候选人的算法题写不出来我也是操碎了心,但是我一般会给足容错,比如给三个算法题,挑一个写,任意写出一个都行)。
所以,你问我算法和数据结构有什么用?我可以很明确的说,和你的年薪息息相关。
时间消耗就对应了:时间复杂度
金钱消耗就对应了:空间复杂度
是否可达就对应了:算法可行性
数据结构 | 应用场景 |
---|---|
数组 | 线性存储、元素为任意相同类型、随机访问 |
字符串 | 线性存储、元素为字符、结尾字符、随机访问 |
链表 | 链式存储、快速删除 |
栈 | 先进后出 |
队列 | 先进先出 |
哈希表 | 随机存储、快速增删改查 |
二叉树 | 对数时间增删改查,二叉查找树、线段树 |
多叉树 | B/B+树 硬盘树、字典树 字符串前缀匹配 |
森林 | 并查集 快速合并数据 |
树状数组 | 单点更新,成段求和 |
答案是:任何一种数据结构是不是 完美的。所以我们需要根据对应的场景,来采用对应的数据结构,具体用哪种数据结构,需要通过刷题不断刷新经验,才能总结出来。
事实证明,立军令状是不可取的。
刷题的第?天 | 目标题数 | 是否完成 | 完成奖励 |
---|---|---|---|
1 | 1 | ? | 攻击力 + 10 |
2 | 1 | ? | 防御力 + 10 |
3 | 2 | ? | 出去吃顿好的 |
4 | 2 | ? | 攻击力 + 29 |
5 | 3 | ? | 防御力 + 60 |
6 | 1 | ? | 攻击力 + 20 |
7 | 4 | ? | 出去吃顿好的 |
8 | 1 | ? | 防御力 + 50 |
如果不知道哪里有水题,推荐:
C语言入门水题:《C语言入门100例》
C语言算法水题:《LeetCode算法全集》
内存结构:内存空间连续
实现难度:简单
下标访问:支持
分类:静态数组、动态数组
插入时间复杂度: O ( n ) O(n) O(n)
查找时间复杂度: O ( n ) O(n) O(n)
删除时间复杂度: O ( n ) O(n) O(n)
内存结构:内存空间连续,类似字符数组
实现难度:简单,一般系统会提供一些方便的字符串操作函数
下标访问:支持
插入时间复杂度: O ( n ) O(n) O(n)
查找时间复杂度: O ( n ) O(n) O(n)
删除时间复杂度: O ( n ) O(n) O(n)
内存结构:内存空间连续不连续,看具体实现
实现难度:一般
下标访问:不支持
分类:单向链表、双向链表、循环链表、DancingLinks
插入时间复杂度: O ( 1 ) O(1) O(1)
查找时间复杂度: O ( n ) O(n) O(n)
删除时间复杂度: O ( 1 ) O(1) O(1)
内存结构:哈希表本身连续,但是衍生出来的结点逻辑上不连续
实现难度:一般
下标访问:不支持
分类:正数哈希、字符串哈希、滚动哈希
插入时间复杂度: O ( 1 ) O(1) O(1)
查找时间复杂度: O ( 1 ) O(1) O(1)
删除时间复杂度: O ( 1 ) O(1) O(1)
内存结构:看用数组实现,还是链表实现
实现难度:一般
下标访问:不支持
分类:FIFO、单调队列、双端队列
插入时间复杂度: O ( 1 ) O(1) O(1)
查找时间复杂度:理论上不支持
删除时间复杂度: O ( 1 ) O(1) O(1)
内存结构:看用数组实现,还是链表实现
实现难度:一般
下标访问:不支持
分类:FILO、单调栈
插入时间复杂度: O ( 1 ) O(1) O(1)
查找时间复杂度:理论上不支持
删除时间复杂度: O ( 1 ) O(1) O(1)
优先队列 是 堆实现的,所以也属于 二叉树 范畴。它和队列不同,不属于线性表。
内存结构:内存结构一般不连续,但是有时候实现的时候,为了方便,一般是物理连续,逻辑不连续
实现难度:较难
下标访问:不支持
分类:二叉树 和 多叉树
插入时间复杂度:看情况而定
查找时间复杂度:理论上 O ( l o g 2 n ) O(log_2n) O(log2n)
删除时间复杂度:看情况而定
内存结构:内存结构一般不连续,但是有时候实现的时候,为了方便,一般是物理连续,逻辑不连续
实现难度:较难
下标访问:不支持
分类:二叉树 和 多叉树
插入时间复杂度:看情况而定
查找时间复杂度:理论上 O ( l o g 2 n ) O(log_2n) O(log2n)
删除时间复杂度:看情况而定
内存结构:不一定
实现难度:难
下标访问:不支持
分类:有向图、无向图
插入时间复杂度:根据算法而定
查找时间复杂度:根据算法而定
删除时间复杂度:根据算法而定
1、图的概念
2、图的存储
1)邻接矩阵
2)邻接表
vector<Edge> edges[maxn];
3)前向星
4)链式前向星
edge[maxm]
,maxm
表示边的总数,所有边都存储在这个结构体数组中,并且用head[i]
来指向 i i i 结点的第一条边。struct Edge {
int u, v, w, next;
Edge() {}
Edge(int _u, int _v, int _w, int _next) :
u(_u), v(_v), w(_w), next(_next)
{
}
}edge[maxm];
head[i] = -1
,当前边总数 edgeCount = 0
;addEdge(u, v, w)
,具体函数的实现如下:void addEdge(int u, int v, int w) {
edge[edgeCount] = Edge(u, v, w, head[u]);
head[u] = edgeCount++;
}
head[i]
就能访问到由 i i i 出发的第一条边的编号,通过编号到edge
数组进行索引可以得到边的具体信息,然后根据这条边的next
域可以得到第二条边的编号,以此类推,直到 next
域为 -1 为止。for (int e = head[u]; ~e; e = edges[e].next) {
int v = edges[e].v;
ValueType w = edges[e].w;
...
}
~e
等价于 e != -1
,是对e
进行二进制取反的操作(-1 的的补码二进制全是 1,取反后变成全 0,这样就使得条件不满足跳出循环)。LeetCode 746. 使用最小花费爬楼梯
数组的每个下标作为一个阶梯,第 i i i 个阶梯对应着一个非负数的体力花费值 c o s t [ i ] cost[i] cost[i](下标从 0 开始)。每当爬上一个阶梯,都要花费对应的体力值,一旦支付了相应的体力值,就可以选择 向上爬一个阶梯 或者 爬两个阶梯。求找出达到楼层顶部的最低花费。在开始时,可以选择从下标为 0 或 1 的元素作为初始阶梯。
样例输入: c o s t = [ 1 , 99 , 1 , 1 , 1 , 99 , 1 , 1 , 99 , 1 ] cost = [1, 99, 1, 1, 1, 99, 1, 1, 99, 1] cost=[1,99,1,1,1,99,1,1,99,1]
样例输出: 6 6 6
如图所以,蓝色的代表消耗为 1 的楼梯,红色的代表消耗 99 的楼梯。
a、思路分析
b. 时间复杂度
c. 代码详解
class Solution {
int f[1100]; // (1)
public:
int minCostClimbingStairs(vector<int>& cost) {
f[0] = 0, f[1] = 0; // (2)
for(int i = 2; i <= cost.size(); ++i) {
f[i] = min(f[i-1] + cost[i-1], f[i-2] + cost[i-2]); // (3)
}
return f[cost.size()];
}
};
f[i]
代表到达第 i i i 层的消耗的最小体力值。有没有发现,这个问题和斐波那契数列很像,只不过斐波那契数列是求和,这里是求最小值。
然后介绍一下刷题顺序的问题,我们刷题的时候千万不要想着一步到位,一开始,没有刷满三百题,姿态放低,都把自己当成小白来处理。
这里以刷 LeetCode 为例,我目前只刷了不到 50 题,所以我是小白。
当我是小白时,我只刷入门题,也就是下面这几个专题。先把上面所有的题目刷完,在考虑下一步要做什么。
种类 | 链接 |
---|---|
算法 | 算法入门 |
数据结构 | 数据结构入门 |
数组字符串专题 | 数组和字符串 |
动态规划专题 | 动态规划入门、DP路径问题 |
当入门的题刷完了,并且都能讲述出来自己刷题的过程以后,我们再来看初级的一些算法和简单的数据结构,简单的数据结构就是线性表了,包含:数组、字符串、链表、栈、队列 等等,即下面这些专题。
种类 | 链接 |
---|---|
算法 | 初级算法 |
栈和队列专题 | 队列 & 栈 |
上面的题刷完以后,其实已经算是基本入门了,然后就可以开始系统性的学习了。
当然,基本如果真的到了这一步,说明你的确已经爱上了刷题了,那么我们可以尝试挑战一下 LeetCode 上的一些热门题,毕竟热门题才是现在面试的主流,能够有更好的结果,这样刷题的时候也会有更加强劲的动力不是吗!
种类 | 链接 |
---|---|
算法 | 中极算法 |
二叉树专题 | 二叉树 |
热门题 | 热门题 TOP 100 |
文章链接 | 难度等级 | 推荐阅读 |
---|---|---|
夜深人静写算法(二)- 动态规划入门 | ★☆☆☆☆ | ★★★★★ |
夜深人静写算法(二十六)- 记忆化搜索 | ★☆☆☆☆ | ★★★★★ |
夜深人静写算法(十九)- 背包总览 | ★☆☆☆☆ | ★★★★★ |
夜深人静写算法(二十)- 最长单调子序列 | ★☆☆☆☆ | ★★★★★ |
夜深人静写算法(二十一)- 最长公共子序列 | ★☆☆☆☆ | ★★★★★ |
夜深人静写算法(二十二)- 最小编辑距离 | ★★☆☆☆ | ★★★★☆ |
夜深人静写算法(十四)- 0/1 背包 | ★☆☆☆☆ | ★★★★☆ |
夜深人静写算法(十五)- 完全背包 | ★★☆☆☆ | ★★★★☆ |
夜深人静写算法(十六)- 多重背包 | ★★☆☆☆ | ★★★★☆ |
夜深人静写算法(二十七)- 区间DP | ★★★☆☆ | ★★★★☆ |
夜深人静写算法(二十九)- 数位DP | ★★★☆☆ | ★★★★★ |
夜深人静写算法(十七)- 分组背包 | ★★★☆☆ | ★★★☆☆ |
夜深人静写算法(十八)- 依赖背包 | ★★★★☆ | ★★☆☆☆ |
夜深人静写算法(六)- RMQ | ★★★☆☆ | ★★☆☆☆ |
树形DP | 待更新 | … |
组合博弈 | 待更新 | … |
组合计数DP | 待更新 | … |
四边形不等式 | 待更新 | … |
状态压缩DP/TSP | 待更新 | … |
斜率优化的动态规划 | 待更新 | … |
插头DP | 待更新 | … |
文章链接 | 难度等级 | 推荐阅读 |
---|---|---|
夜深人静写算法(一)- 搜索入门 | ★☆☆☆☆ | ★★★☆☆ |
夜深人静写算法(八)- 二分图最大匹配 | ★★☆☆☆ | ★★☆☆☆ |
最大团 | 待更新 | … |
最小生成树 | 待更新 | … |
树的分治 | 待更新 | … |
迭代加深 IDA* | 待更新 | … |
有向图强连通分量和2-sat | 待更新 | … |
无向图割边割点 | 待更新 | … |
带权图的二分图匹配 | 待更新 | … |
哈密尔顿回路 | 待更新 | … |
最近公共祖先 | 待更新 | … |
欧拉回路圈套圈 | 待更新 | … |
最小费用最大流 | 待更新 | … |
最小树形图 | 待更新 | … |
2、广度优先搜索
文章链接 | 难度等级 | 推荐阅读 |
---|---|---|
夜深人静写算法(十)- 单向广搜 | ★★☆☆☆ | ★★★★☆ |
夜深人静写算法(二十三)- 最短路 | ★★★☆☆ | ★★★★☆ |
夜深人静写算法(二十五)- 稳定婚姻 | ★★☆☆☆ | ★★☆☆☆ |
夜深人静写算法(二十四)- 最短路径树 | ★★★☆☆ | ★☆☆☆☆ |
K 短路 | 待更新 | … |
差分约束 | 待更新 | … |
拓扑排序 | 待更新 | … |
A* | 待更新 | … |
双向广搜 | 待更新 | … |
最大流 最小割 | 待更新 | … |
文章链接 | 难度等级 | 推荐阅读 |
---|---|---|
夜深人静写算法(三)- 初等数论入门 | ★★☆☆☆ | ★★★★☆ |
夜深人静写算法(三十)- 二分快速幂 | ★☆☆☆☆ | ★★★★★ |
夜深人静写算法(三十一)- 欧拉函数 | ★★★☆☆ | ★★★★★ |
夜深人静写算法(三十二)- 费马小定理 | ★★☆☆☆ | ★★★☆☆ |
夜深人静写算法(三十三)- 扩展欧拉定理 | ★★★☆☆ | ★★★★☆ |
夜深人静写算法(三十四)- 逆元 | ★★★☆☆ | ★★★★☆ |
夜深人静写算法(三十五)- RSA 加密解密 | ★★★☆☆ | ★★★★★ |
夜深人静写算法(三十六)- 中国剩余定理 | ★★☆☆☆ | ★★★☆☆ |
夜深人静写算法(三十七)- 威尔逊定理 | ★★☆☆☆ | ★★★☆☆ |
夜深人静写算法(三十八)- 整数分块 | ★★☆☆☆ | ★★★★☆ |
卢卡斯定理 | 待更新 | … |
狄利克雷卷积 | 待更新 | … |
莫比乌斯反演 | 待更新 | … |
容斥原理 | 待更新 | … |
拉宾米勒 | 待更新 | … |
Pollard rho | 待更新 | … |
莫队 | 待更新 | … |
原根 | 待更新 | … |
大步小步算法 | 待更新 | … |
二次剩余 | 待更新 | … |
矩阵二分快速幂 | 待更新 | … |
Polya环形计数 | 待更新 | … |
饭不食,水不饮,题必须刷
C语言免费动漫教程,和我一起打卡! 《光天化日学C语言》
LeetCode 太难?先看简单题! 《C语言入门100例》
数据结构难?不存在的! 《画解数据结构》
LeetCode 太简单?算法学起来! 《夜深人静写算法》