济公学院算法笔记
算法学习
1.数据结构及应用
数据结构只是工具,用来解决问题的,因此要熟悉并选用对应的数据结构来解决实际问题。
- 线性数据结构
-
可变数组-例如Java中的ArrayList、Deque
队列:例如 BFS
栈:例如两个栈模拟表达式或者无递归的DFS
链表:插入排序或者并查集
- 二分堆
共有三种操作,getMin(复杂度为O(1)), deleteMin(复杂度为O(logn)), insert(复杂度为O(logn))。最经典的应用是堆排序,在Java中的实现方式是PriorityQueue。可以用作LRU,在面试中可以用BST来代替map操作
- 二分搜索树(BST)
在Java中的应用主要是TreeSet和TreeMap,跟HashTable不一样,HashTable不是有序的。BST能实现二分堆的所有内容,就只是getMin()方法效率会低一点。非常适合用于找某值最近的两个数。其他应用:查询(滑动窗口)kth的值(用两个BST或有迭代器的BST实现)
- 前缀树(Trie)
目标是查询动态词典,如果是静态词典,可以用二分查找
- 后缀树和后缀数组
- 统计一个范围内相关的数据,比如一个范围内的和,一个范围内的所有值的最小值、抑或等等,可以用二分统计树等等,相当于打标签
2.图上的深度和广度优先搜索
1.隐式图上的搜索模型
- 隐式图:从起点可到达的状态(顶点)在搜索开始前未知
- Depth-First Search:从起点找到一个或者所有的终结状态,空间复杂度取决于最大深度会不会导致堆栈溢出
- Breadth-First Search:从起点找到一个最近的终结状态,不一定要用queue,也可以试试用ArrayList,空间复杂度取决于一层的最大宽度
2.DFS template
- DFS的参数中状态和路径在前,常量在后
- 在递归后注意恢复递归前的环境
dfs(current_state, path, constants){
//mark visited
visited[current_state] = true;
//judge terminated
if(is_terminate(current_state)){
solution.add(path);
return;
}
//loop actions
for(next_state, action/edge in transition(current_state)){
if(visited(next_state)) continue;
path.push_back(action/edge);
dfs(next_state, path, constants);
path.pop_back();
}
}
e.g.
class State{int Wa; int Wb;};
typedef enum(FILL_A, FILL_B, EMPTY_A, EMPTY_B, POUR_AB, POUR_BA) Action;
vector<pair<State, Action>> transition(State current_state){
result.push_back(pair(State(Ca, current_state.Wb), FILL_A));
result.push_back(pair(State(current_state.Wa, Cb), FILL_B));
}
3.BFS Template
bfs(start_state){
queue.push(start_state);
meta_data[start_state] = {
visited = true, pre_state = node, pre_action = none
};
while(queue is not empty){
current_state = queue.pop_front();
if(is_terminate(current_state)){
solution.add(path constructed from meta_data);
return;
}
for(next_state, action/edge in transition(current_state)){
if(meta_data[next_state].visited) continue;
queue.push_back(next_state);
meta_data[next_state] = {
visited = true,
pre_state = current_state,
pre_action = action/edge
};
}
}
}
BFS的扩展应用 - 0-1图上的最短路径,用两个queue(weight是0的形成一个queue,是1的形成另一个queue)或者deque(为0的放左边,为1的放右边)
4.搜索优化
-
状态定义(e.g. high dimensional states 高维状态)和存储(e.g. Bitwise representation 使用位运算 or State Presenting combinations 多个参数组合表示状态)最优
-
transition过程是清晰和优化过的
-
搜索顺序和剪枝(Pruning)的优化(e.g. A* or IDA*)
-
DFS中朴素的剪枝
-
BFS中的过河拆桥(避免BFS中的重复搜索 e.g.如果有一个顶点不满足条件,那这一类的顶点都可以不再继续考虑)
-
-
部分记忆化搜索去避免重复搜索(DFS/BFS和记忆化搜索结合,与纯DP不同,因为DP可能内存不够)
-
双向搜索
5.答疑
-
不是所有可以DP的方法都能BFS
-
DP的状态转移一定是单向的有顺序的,不能有环
-
搜索都解决不了太大规模的问题,因为是指数级的,一般用64位的整数就能表达所有问题
-
显式图上(类似于一维数组二维数组)的dp就用简单的dp写循环,如果是隐式图上的dp就应该用dfs+memorization
-
有时候最优解不需要所有状态,这时候也可以用dfs+memorization
-
递归不如循环好调
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix