leetcode BFS的代码框架实现的题目
学习心得:
- 算法小抄里面有这样的一句话,对二叉树的操作可以衍生出很多算法思想,题刷的越来越多,体会也就越来越多
- 在二叉树遍历也也是两种形式,DFS和BFS,DFS中包含了前中后序的三种遍历形式,BFS只有层级遍历这一种,
- 层级遍历分类型,应用不同数据结构来衍生出不同的遍历顺序,可以做一下剑指offer中的32题,去具体的操作队列
- 对DFS和BFS目操作之间也存在一定的关联,但是也就是把待处理加到容器中,再从容器中拿到对应的数据进行处理,BFS是队列,DFS是栈
- 换个思路,这个容器随便改,便会有各种不同的搜索算法,放在一个堆中,就生成了一个最小生成树,放到一个随机的容器中,就更好玩了,等等
DFS的代码框架思路:
- 创建核心的数据结构队列 一个visit的set避免走过多的回头路
- 将起点加入到队列中,visit设置为true
- 打入队列的内部,取出起点进行路径的扩散,同时判断时候达到了终点,
- 将节点相邻的队列加入队列,更新所求的极值
代码框架如下:
int BFS(Node start,Node target){
Queue<node> queue;//核心的数据结构
Set<Node> visited;//避免走回头路
queue.offer(start);//将起点加入队列
visited.add(start);
int step = 0;//记录扩散的步数
while(q not empty){
int sz = queue.size();
//将当前队列中的所有节点向四周扩散
for (int i = 0; i < sz; i++) {
Node cur = queue.poll();
//判断时候达到了终点
if (cur is target){
return step;
}
//将cur的相邻节点添加队列
for (Node x : cur.adj()){
if (x not in visited){
queue.offer(x);
visited.add(x)
}
}
}
//划重点,更新步数在这里
step++;
}
}
leetcode第111题 二叉树的最小深度
心得:
-
做这个题目之前我是做过求二叉树的最大深度这个题目的,用相同的方式进行思考,但是出现的错误,没有考虑到根节点的左子节点或是右子节点为null的情况
-
bfs的核心框架是不难理解的,就是把一些问题抽象成图,从一个点开始,向四周扩散,
-
BFS和DFS的最主要区别是:BFS找到的相对路径一定是最短的,但代价就是空间复杂度比DFS大很多,
-
为什么BFS可以找到最短的距离吗,DFS不行吗?
首先,你看BFS的逻辑,depth每增加一次,队列中的所有节点都会向前迈一步,这保证了第一次到达终点的时候,走的步数是最少的。
DFS不能找见最短路径么?其实也是可以的,但是相对来说,时间复杂度就会高出很多,DFS实际上是靠着递归的堆栈记录走过所有路径,肯定是需要把二叉树中的所有的树杈都搜索网进行比较才能够得出最短的路径有多长
而BFS借助队列做到一次一步,齐头并进,是可以在不遍历完整个树的条件下找到最短距离的
-
lass Solution {
public int minDepth(TreeNode root) {
//我就直接就是纳了闷了 为什么这些问题我就是不会做了,真的是气死我了啊!
//二叉树其实是很简单的数据结构,广度优先首先其实就是应用的数据结构不同,而深度优先是应用的队列
if (root == null){
return 0;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int depth = 1;
while(!queue.isEmpty()){
int sz = queue.size();
for(int i = 0;i < sz;i++){
TreeNode curnode = queue.poll();
if (curnode.right == null && curnode.left == null){
return depth;
}
if (curnode.left != null){
queue.offer(curnode.left);
}
if (curnode.right != null){
queue.offer(curnode.right);
}
}
depth++;
}
return depth;
}
}
leetcode第752题,打开转盘锁
思路:
1. 这个题目的难点在于,不能出现deadends,应该如何计算最短的路径,
2. 我们不管所有的限制条件,不管deadend和target的限制,就思考一个问题,如果让你设计一个算法,穷举出所有的密码组合,你会怎么搞
3. 穷举呗,再简单一点,如果你只需要转动一下锁,有几种可能,总共有4个位置,每个位置可以向上转,也可以向下转,也就是有八种可能,
4. 从0000开始,转一次可以穷举出1000 9000 0100 0900 ...这八种密码,然后再用密码作为基础,每个密码在转一下,穷举出所有的可能性
5. 仔细想想,这就可以抽象出来一幅图,每个节点都有八个相邻的节点,又让你求最短的距离,这不就是典型的BFS么,框架就可以派上用厂了
class Solution {
public int openLock(String[] deadends, String target) {
//存储我们需要跳过的死亡密码
HashSet<String> deads = new HashSet<>();
for (String deadend : deadends) {
deads.add(deadend);
}
// 备忘录查看,我们是否添加过这个字符串
HashSet<String> memo = new HashSet<>();
//应用队列这种数据结构搭建一个bfs的算法框架
Queue<String> queue = new LinkedList<>();
//添加其实的我们转动的密码
queue.offer("0000");
memo.add("0000");
//从起点开始进行广度优先遍历搜索
int step = 0;
while (!queue.isEmpty()) {
int sz = queue.size();
//将当前队列中的所有节点向周围扩散.
for (int i = 0; i < sz; i++) {
String curStr = queue.poll();
//判断时候经过了我们的死亡密码
if (deads.contains(curStr)) {
continue;
}
//判断时候到达了终点
if (curStr.equals(target)) {
return step;
}
//从遍历的节点开始,添加队列
for (int j = 0; j < 4; j++) {
String up = turnUp(curStr, j);
if(!memo.contains(up)){
queue.offer(up);
memo.add(up);
}
String down = turnDown(curStr, j);
if (!memo.contains(down)) {
queue.offer(down);
memo.add(down);
}
}
}
//在这里增加步数
step++;
}
return -1;
}
//先写向上转动的方法
public String turnUp(String str,int j){
char[] chars = str.toCharArray();
if (chars[j] == '9'){
chars[j] = '0';
}else{
chars[j] += 1;
}
return new String(chars);
}
public String turnDown(String str,int j){
char[] chars = str.toCharArray();
if (chars[j] == '0'){
chars[j] = '9';
}else{
chars[j] -= 1;
}
return new String(chars);
}
}