文章目录
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/0b43dbe97c307873fae3106af6e17b71.png)
本文参考 - 知乎
- 10个数据结构:数组、链表、栈、队列、散列表、二叉树、堆、
跳表、图、Trie 树
- 10个算法:递归、排序、二分查找、搜索、
哈希算法
、贪心算法、分治算法、回溯算法、动态规划、字符串匹配算法
复杂度
- 常数阶O(1)
- 线性阶O(n)
- 平方阶O(n²)
- 对数阶O(logn)
- 线性对数阶O(nlogn)
常见算法复杂度
常见算法思想
贪心
从问题的某一初始解出发
while (能朝给定总目标前进一步)
do
选择当前最优解作为可行解的一个解元素;
由所有解元素组合成问题的一个可行解。
动态规划
- 流程
问题拆解,找到问题之间的具体联系
状态定义
- 递推方程推导
- 实现
- DP
- 解动态规划题目其实就是拆解问题,定义状态的过程,严格说来,动态规划并不是一个具体的算法,而是凌驾于算法之上的一种 思想
- 从局部最优解通过一定的策略推得全局最优解,从子问题的答案一步步推出整个问题的答案,并且利用空间换取时间
120. 三角形最小路径和
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
int N = triangle.size();
int dp[N][N];
for (int i = 0; i < N; i++)
dp[N-1][i] = triangle[N-1][i];
for (int i = N - 2; i >= 0; i--) {
for (int j = 0; j < triangle[i].size(); j++) {
dp[i][j] = min(dp[i+1][j], dp[i+1][j+1]) + triangle[i][j];
}
}
return dp[0][0];
}
};
256. 粉刷房子
class Solution {
public:
int minCost(vector<vector<int>>& costs) {
int r = 0, b = 0, g = 0;
for (auto& c : costs) {
int r0 = min(c[0]+b, c[0]+g);
int b0 = min(c[1]+r, c[1]+g);
int g0 = min(c[2]+r, c[2]+b);
r = r0; b = b0; g = g0;
}
return min(r, min(b, g));
}
};
265. 粉刷房子II
分治策略
- 对于一个规模为 n 的问题,若该问题可以容易地解决(比如说规模 n 较小)则直接解决,否则将其分解为 k 个规模较小的子问题,这些子问题互相独立且与原问题形式相同,递归地解这些子问题,然后将各子问题的解合并得到原问题的解
T(n)= k T(n/m) + f(n)
Divide-and-Conquer(P)
if |P| ≤ n0
then return(ADHOC(P))
将P分解为较小的子问题 P1 ,P2 ,...,Pk
for i←1 to k
do yi ← Divide-and-Conquer(Pi) △ 递归解决Pi
T ← MERGE(y1,y2,...,yk) △ 合并子问题
return(T)
- 二分查找
- 归并排序
- 快速排序
- 汉诺塔递归
- 递归和动规
KMP算法
- 动态规划构图,也可以使用递归和带备忘录的递归
参考
排序
十大排序算法
搜索
拓扑排序
- 拓扑排序就是根据这些依赖来给出一个做事情,或者是事件的一个顺序
- BFS/DFS
查找
- 二分查找
字符串匹配
Boyer-Moore 算
- 简称 BM 算法
- 从模式串的尾部开始匹配,且拥有在最坏情况下 O(N) 的时间复杂度。有数据表明,在实践中,比 KMP 算法的实际效能高,可以快大概 3-5 倍。
- 它是基于以下两个规则让模式串每次向右移动 尽可能大 的距离。
- 坏字符规则(bad-character shift):当文本串中的某个字符跟模式串的某个字符不匹配时,我们称文本串中的这个失配字符为坏字符,此时模式串需要向右移动,移动的位数 = 坏字符在模式串中的位置 - 坏字符在模式串中最右出现的位置。此外,如果"坏字符"不包含在模式串之中,则最右出现位置为 -1。坏字符针对的是文本串。
- 好后缀规则(good-suffix shift):当字符失配时,后移位数 = 好后缀在模式串中的位置 - 好后缀在模式串上一次出现的位置,且如果好后缀在模式串中没有再次出现,则为 -1。好后缀针对的是模式串。
KMP算法
- Knuth-Morris-Pratt 字符串查找算法,简称为 KMP算法,常用于在一个文本串 S 内查找一个模式串 P 的出现位置。
Brute-Force算法
- BF算法
- 流程:
- 对于给定的主串 S 与子串 P ,主串 S 的长度为 N,子串 T 的长度为 M ;
- 首先,将 S[1] 和 T[1] 进行比较;
- 若相等,则再比较 S[2] 和 T[2] ,一直到 T[M] 为止;
- 若 S[1] 和 T[1] 不等,则 T 向右移动一个字符的位置,再依次进行比较;
- 缺点:BF算法 在主串和字串匹配失败时,主串进行的回溯操作会影响效率,回溯之后,主串与字串有些部分比较是没有必要的。这种简单的丢弃前面的匹配信息是 BF算法 之所以效率低效的一个重要因素。
数据
线性表
散列表
- 哈希洪水攻击(Hash-Flooding Attack)?
- 布隆过滤(Bloom Filter):现在有一个非常庞大的数据,假设全是 int 类型。现在我给你一个数,你需要告诉我它是否存在其中(尽量高效)。
- 它主要就是用于解决判断一个元素是否在一个集合中,但它的优势是只需要占用很小的内存空间以及有着高效的查询效率。
树
- 各种树:参考
二叉树
B树
2-3树 / 2-3-4树
字典树(Trie树)
- Trie 树,也叫“字典树”。顾名思义,它是一个树形结构。它是一种专门处理字符串匹配的数据结构,用来解决在一组字符串集合中快速查找某个字符串的问题。
- Trie 树也称前缀树(因为某节点的后代存在共同的前缀,比如pan是panda的前缀)
- 它的key都为字符串,能做到高效查询和插入,时间复杂度为O(k),k为字符串长度,缺点是如果大量字符串没有共同前缀时很耗内存
- 核心思想就是通过最大限度地减少无谓的字符串比较,使得查询高效率,即「用空间换时间」,再利用共同前缀来提高查询效率
- 特点
- 根节点不包含字符,除根节点外每一个节点都只包含一个字符
- 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串
- 每个节点的所有子节点包含的字符都不相同
- 字典树的两大基本用法:
- 确认一个单词是否在字典中存在
- 确认字典中是否含有某前缀的单词
- 求得字典中含有某前缀的所有单词
- 计算字典中含有某前缀的单词的个数
- 计算字典中含有某前缀的单词的出现频率