关于bfs:BFS算法模板与练习

文章和代码曾经归档至【Github仓库:algorithms-notes】或者公众号【AIShareLab】回复 算法笔记 也可获取。首先,计算机中罕用的数据结构是栈和队列。 栈:先进后出,通常利用是递归,DFS。队列:先进先出,通常利用是 BFS 。过程如下所示: 每次取出队头元素,并且把其拓展的元素放在队尾。 下面过程可知,遍历的过程以及入队的过程都是依照BFS(1 2 3...10)的程序进行的 BFS宽搜:每次扩大最早的点。(因而能够找到一条最短的门路) DFS深搜:每次扩大第一个点。 BFS中常见问题,迷宫问题。 模板1.判重 入队时判重,保障每个边只会入队一次,从而保障工夫复杂度是线性的。(因而有判重数组的存在,宽搜也能够搜寻环),st[ ]。 2.队列 queue <--- 初始状态 // 队列保留初始状态while(queue 非空){ t < --- 队头 // t保留队头 for(拓展t) { ver < --- 新节点 // 拓展t失去的新节点 if(!st[ver]) // 如果拓展的新节点没有被搜寻过 { ver ----> 队尾 // 保留至队尾 } }}献给阿尔吉侬的花束阿尔吉侬是一只聪慧又慵懒的小白鼠,它最善于的就是走各种各样的迷宫。 明天它要挑战一个十分大的迷宫,研究员们为了激励阿尔吉侬尽快达到起点,就在起点放了一块阿尔吉侬最喜爱的奶酪。 当初研究员们想晓得,如果阿尔吉侬足够聪慧,它起码须要多少工夫就能吃到奶酪。 迷宫用一个 R×C 的字符矩阵来示意。 字符 S 示意阿尔吉侬所在的地位,字符 E 示意奶酪所在的地位,字符 # 示意墙壁,字符 . 示意能够通行。 阿尔吉侬在 1 个单位工夫内能够从以后的地位走到它上下左右四个方向上的任意一个地位,但不能走出地图边界。 输出格局 第一行是一个正整数 T,示意一共有 T 组数据。 ...

March 21, 2023 · 3 min · jiezi

leetcode407-Trapping-Rain-Water-II

题目要求Given an m x n matrix of positive integers representing the height of each unit cell in a 2D elevation map, compute the volume of water it is able to trap after raining. Note:Both m and n are less than 110. The height of each unit cell is greater than 0 and is less than 20,000. Example:Given the following 3x6 height map:[ [1,4,3,1,3,2], [3,2,1,3,2,4], [2,3,3,2,3,1]]Return 4. ...

October 3, 2019 · 2 min · jiezi

leetcode433-Minimum-Genetic-Mutation

题目要求A gene string can be represented by an 8-character long string, with choices from "A", "C", "G", "T".Suppose we need to investigate about a mutation (mutation from "start" to "end"), where ONE mutation is defined as ONE single character changed in the gene string.For example, "AACCGGTT" -> "AACCGGTA" is 1 mutation.Also, there is a given gene "bank", which records all the valid gene mutations. A gene must be in the bank to make it a valid gene string.Now, given 3 things - start, end, bank, your task is to determine what is the minimum number of mutations needed to mutate from "start" to "end". If there is no such a mutation, return -1.Note:Starting point is assumed to be valid, so it might not be included in the bank.If multiple mutations are needed, all mutations during in the sequence must be valid.You may assume start and end string is not the same. Example 1:start: "AACCGGTT"end: "AACCGGTA"bank: ["AACCGGTA"]return: 1 Example 2:start: "AACCGGTT"end: "AAACGGTA"bank: ["AACCGGTA", "AACCGCTA", "AAACGGTA"]return: 2 Example 3:start: "AAAAACCC"end: "AACCCCCC"bank: ["AAAACCCC", "AAACCCCC", "AACCCCCC"]return: 3假设现在有两个基因序列,并且用一个字符串数组bank来表示一个基因序列银行。已知每一步可以将当前基因序列中的一位进行改变,变成另一个已知的基因序列。问最少需要多少步可以将初始的基因序列转化为目标基因序列。如果无法转换,则返回-1。 ...

August 8, 2019 · 2 min · jiezi

广度优先深度优先寻求最短路径

深度优先遍历,广度优先遍历,寻求最短路径本例使用邻接矩阵 public class GraphTest { // 节点 public static class Vertex { public String name; private boolean isVisited; public Vertex(String name) { this.name = name; this.isVisited = false; } public void displayName() { System.out.println("name:" + name); } } // 图 public static class Graph { // 存节点数据 private Vertex[] vertices; // 矩阵 private int[][] matrix; // 队列,用于BFS private Queue<Integer> queue = new LinkedList<>(); // 栈,用于DFS private Stack<Integer> stack = new Stack<>(); private Map<Integer, Integer> dependencyMap = new HashMap<>(); public Graph(Vertex[] vertices, int[][] matrix) { this.vertices = vertices; this.matrix = matrix; } // 找到未访问过的邻接点 public List<Integer> getUnvisitedVertex(int i) { List<Integer> unvisitedVertices = new ArrayList<>(); for (int j = 0; j < matrix.length; j++) { if (matrix[i][j] > 0 && !vertices[j].isVisited) { unvisitedVertices.add(j); } } return unvisitedVertices; } // 广度优先 public void bfs(int vertex) { queue.offer(vertex); while (!queue.isEmpty()) { int v = queue.poll(); if (!vertices[v].isVisited) { vertices[v].displayName(); vertices[v].isVisited = true; List<Integer> unvisitedVertices = getUnvisitedVertex(v); unvisitedVertices.forEach(uv -> { queue.offer(uv); dependencyMap.putIfAbsent(uv, v); }); } } } // 深度优先 public void dfs(int vertex) { stack.push(vertex); while (!stack.isEmpty()) { int v = stack.pop(); if (!vertices[v].isVisited) { vertices[v].displayName(); vertices[v].isVisited = true; List<Integer> unvisitedVertices = getUnvisitedVertex(v); unvisitedVertices.forEach(uv -> stack.push(uv)); } } } // 深度优先递归实现 public void dfsRecursion(int vertex) { if (!vertices[vertex].isVisited) { vertices[vertex].displayName(); vertices[vertex].isVisited = true; List<Integer> unvisitedVertices = getUnvisitedVertex(vertex); unvisitedVertices.forEach(this::dfsRecursion); } } public void printShortestPath(int start, int end) { bfs(start); String symbol = "-->"; StringBuilder sb = new StringBuilder(); sb.append(vertices[end].name); sb.append(symbol); while (dependencyMap.get(end) != null) { sb.append(vertices[dependencyMap.get(end)].name); sb.append(symbol); end = dependencyMap.get(end); } String path = sb.substring(0, sb.lastIndexOf(symbol)); System.out.println(path); } public void clear() { stack.clear(); queue.clear(); dependencyMap.clear(); for (int i = 0; i < vertices.length; i++) { vertices[i].isVisited = false; } } } public static void main(String[] args) { Vertex[] vertices = { new Vertex("v0"), new Vertex("v1"), new Vertex("v2"), new Vertex("v3"), new Vertex("v4") }; int[][] matrix = new int[][]{ {0, 0, 1, 1, 0}, {0, 0, 1, 0, 1}, {1, 1, 0, 0, 1}, {1, 0, 0, 0, 1}, {0, 1, 1, 1, 0} }; Graph graph = new Graph(vertices, matrix); System.out.println("广度优先搜索:"); graph.bfs(0); graph.clear(); System.out.println("深度优先搜索:"); graph.dfs(0); graph.clear(); System.out.println("递归深度优先搜索:"); graph.dfsRecursion(0); graph.clear(); System.out.println("打印最短路径:"); graph.printShortestPath(0, 4); }}打印结果广度优先搜索:name:v0name:v2name:v3name:v1name:v4深度优先搜索:name:v0name:v3name:v4name:v2name:v1递归深度优先搜索:name:v0name:v2name:v1name:v4name:v3打印最短路径:name:v0name:v2name:v3name:v1name:v4v4-->v2-->v0 ...

July 11, 2019 · 2 min · jiezi

leetcode417-Pacific-Atlantic-Water-Flow

题目要求Given an m x n matrix of non-negative integers representing the height of each unit cell in a continent, the "Pacific ocean" touches the left and top edges of the matrix and the "Atlantic ocean" touches the right and bottom edges.Water can only flow in four directions (up, down, left, or right) from a cell to another one with height equal or lower.Find the list of grid coordinates where water can flow to both the Pacific and Atlantic ocean.Note:The order of returned grid coordinates does not matter.Both m and n are less than 150.Example:Given the following 5x5 matrix: Pacific ~ ~ ~ ~ ~ ~ 1 2 2 3 (5) * ~ 3 2 3 (4) (4) * ~ 2 4 (5) 3 1 * ~ (6) (7) 1 4 5 * ~ (5) 1 1 2 4 * * * * * * AtlanticReturn:[[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]] (positions with parentheses in above matrix).假设左上角的所有周围面积为太平洋,右下角的所有面积为大西洋。现在使用数组来表示一大片水域,其中数组的每一个位置上的元素代表某一个小水域的高度。假定水只能从高出流向低处,要求找出所有既可以流向太平洋也可以流向大西洋的水域。 ...

June 1, 2019 · 2 min · jiezi

leetcode403. Frog Jump

题目要求A frog is crossing a river. The river is divided into x units and at each unit there may or may not exist a stone. The frog can jump on a stone, but it must not jump into the water.Given a list of stones’ positions (in units) in sorted ascending order, determine if the frog is able to cross the river by landing on the last stone. Initially, the frog is on the first stone and assume the first jump must be 1 unit.If the frog’s last jump was k units, then its next jump must be either k - 1, k, or k + 1 units. Note that the frog can only jump in the forward direction.Note:The number of stones is ≥ 2 and is < 1,100.Each stone’s position will be a non-negative integer < 231.The first stone’s position is always 0.Example 1:[0,1,3,5,6,8,12,17]There are a total of 8 stones.The first stone at the 0th unit, second stone at the 1st unit,third stone at the 3rd unit, and so on…The last stone at the 17th unit.Return true. The frog can jump to the last stone by jumping 1 unit to the 2nd stone, then 2 units to the 3rd stone, then 2 units to the 4th stone, then 3 units to the 6th stone, 4 units to the 7th stone, and 5 units to the 8th stone.Example 2:[0,1,2,3,4,8,9,11]Return false. There is no way to jump to the last stone as the gap between the 5th and 6th stone is too large.假设有一只青蛙需要过河,河中会有一些石子,青蛙必须踩在石头上才算成功。石头的位置用整数数组来表示。青蛙的行走规则为:假设上一次青蛙跳了k格,则当前青蛙只能跳k-1或k或k+1格,且青蛙只能向前跳,不能向后跳。广度优先遍历可以从起点开始,对从该点出发的所有可能步数进行遍历,并更新从该点可达的点的所有的可行步数。利用Map<Integer, Set<Integer>>数据结构来记录该结果,其中map的key为stone的unit数,它的value对应的是从该key出发的所有的上一步的步长。该遍历思路类似于广度优先遍历,即将该点出发遍历所有的可达点。代码如下: public boolean canCross(int[] stones) { if(stones.length < 2) return true; if(stones.length == 2 && stones[1] == 1) return true; if(stones.length >= 2 && stones[1] != 1) return false; Map<Integer, Set<Integer>> stoneJump = new HashMap<>(); for(int i = 1 ; i<stones.length ; i++) { stoneJump.put(stones[i], new HashSet<>()); } stoneJump.get(1).add(1); int finalStone = stones[stones.length-1]; boolean hasNext = false; for(int i = 1 ; i<stones.length; i++) { for(int step : stoneJump.get(stones[i])) { int next = stones[i] + step - 1; for(int addOn = -1 ; addOn <= 1 ; addOn++) { if(step + addOn != 0) { if(next == finalStone) { return true; } if(stoneJump.containsKey(next)) { stoneJump.get(next).add(step + addOn); hasNext = true; } } next++; } } if(!hasNext) break; hasNext = false; } return false; }深度优先遍历和上一种思路的区别在于,这种方法会尽可能往远处遍历。即只要该点可以到达下一点,则会立刻尝试从一点到达终点。代码如下: public boolean canCross(int[] stones) { for(int i = 1 ; i<stones.length ; i++) { if(stones[i] - stones[i-1] > i) return false; } return canCross2(stones, 1, 1); } public boolean canCross2(int[] stones, int idx, int lastStep) { if(idx == stones.length-1) return true; if(idx < 0 || lastStep <= 0) return false; for(int jump = lastStep + 1 ; jump >= lastStep -1 ; jump–) { if(canCross2(stones, Arrays.binarySearch(stones, stones[idx] + jump), jump)){ return true; } } return false; } ...

April 18, 2019 · 3 min · jiezi

[LeetCode] 364. Nested List Weight Sum II

ProblemGiven a nested list of integers, return the sum of all integers in the list weighted by their depth.Each element is either an integer, or a list – whose elements may also be integers or other lists.Different from the previous question where weight is increasing from root to leaf, now the weight is defined from bottom up. i.e., the leaf level integers have weight 1, and the root level integers have the largest weight.Example 1:Input: [[1,1],2,[1,1]]Output: 8 Explanation: Four 1’s at depth 1, one 2 at depth 2.Example 2:Input: [1,[4,[6]]]Output: 17 Explanation: One 1 at depth 3, one 4 at depth 2, and one 6 at depth 1; 13 + 42 + 6*1 = 17.Solutionclass Solution { public int depthSumInverse(List<NestedInteger> nestedList) { int preSum = 0, sum = 0; Queue<NestedInteger> queue = new LinkedList<>(); for (NestedInteger i: nestedList) queue.offer(i); while (!queue.isEmpty()) { int size = queue.size(); int curSum = 0; while (size– > 0) { NestedInteger i = queue.poll(); if (i.isInteger()) curSum += i.getInteger(); else { for (NestedInteger j: i.getList()) queue.offer(j); } } preSum += curSum; sum += preSum; } return sum; }}APIs:/** * // This is the interface that allows for creating nested lists. * // You should not implement it, or speculate about its implementation * public interface NestedInteger { * // Constructor initializes an empty nested list. * public NestedInteger(); * * // Constructor initializes a single integer. * public NestedInteger(int value); * * // @return true if this NestedInteger holds a single integer, rather than a nested list. * public boolean isInteger(); * * // @return the single integer that this NestedInteger holds, if it holds a single integer * // Return null if this NestedInteger holds a nested list * public Integer getInteger(); * * // Set this NestedInteger to hold a single integer. * public void setInteger(int value); * * // Set this NestedInteger to hold a nested list and adds a nested integer to it. * public void add(NestedInteger ni); * * // @return the nested list that this NestedInteger holds, if it holds a nested list * // Return null if this NestedInteger holds a single integer * public List<NestedInteger> getList(); * } */ ...

December 28, 2018 · 2 min · jiezi

[LeetCode] 130. Surrounded Regions

ProblemGiven a 2D board containing ‘X’ and ‘O’ (the letter O), capture all regions surrounded by ‘X’.A region is captured by flipping all ‘O’s into ‘X’s in that surrounded region.Example:X X X XX O O XX X O XX O X XAfter running your function, the board should be:X X X XX X X XX X X XX O X XExplanation:Surrounded regions shouldn’t be on the border, which means that any ‘O’ on the border of the board are not flipped to ‘X’. Any ‘O’ that is not on the border and it is not connected to an ‘O’ on the border will be flipped to ‘X’. Two cells are connected if they are adjacent cells connected horizontally or vertically.Solutionclass Solution { public void solve(char[][] board) { if (board == null || board.length == 0 || board[0].length == 0) return; int m = board.length, n = board[0].length; int[][] dirs = {{-1,0},{1,0},{0,-1},{0,1}}; boolean[][] visited = new boolean[m][n]; //optional for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if ((i == 0 || i == m-1 || j == 0 || j == n-1) && board[i][j] == ‘O’ && !visited[i][j]) { Queue<int[]> queue = new LinkedList<>(); board[i][j] = ‘B’; //visited[i][j] = true; queue.offer(new int[]{i, j}); while (!queue.isEmpty()) { int[] cur = queue.poll(); for (int k = 0; k < 4; k++) { int x = cur[0] + dirs[k][0]; int y = cur[1] + dirs[k][1]; if (x < 0 || x >= m || y < 0 || y >= n || board[x][y] != ‘O’ || visited[x][y]) continue; board[x][y] = ‘B’; //visited[x][y] = true; queue.offer(new int[]{x, y}); } } } } } for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (board[i][j] == ‘O’) board[i][j] = ‘X’; else if (board[i][j] == ‘B’) board[i][j] = ‘O’; } } }} ...

December 25, 2018 · 2 min · jiezi