这类题是最简单的了都是一个套路,不像动态规划一类题一个套路,没做过就是不会也极难想出来。

一、BFS

解决的问题:用来初始点解决到指定点的最短路径问题,因为图的每一层上的点到初始点的距离相同。(注意是无权图)

在程序实现 BFS 时需要考虑以下问题:

  • 队列:用来存储每一轮遍历得到的节点;
  • 标记:对于遍历过的节点,应该将它标记,防止重复遍历。

下面这两个题都是比较典型的广度优先题

1091. 二进制矩阵中的最短路径

这题笔者超时了百思不得其解。

class Solution {
public int shortestPathBinaryMatrix(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
if(grid[0][0] == 1 || grid[m-1][n-1] == 1) return -1;
int[][] dirc = {{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};
LinkedList<int[]> queue = new LinkedList<>();
queue.add(new int[]{0,0,1});
while(!queue.isEmpty()) {
int[] p = queue.poll();
if(p[0]==m-1 && p[1]==n-1) return p[2];
grid[p[0]][p[1]] = 1;
for(int[] d : dirc) {
int x = p[0] + d[0];
int y = p[1] + d[1];
if(x<0||y<0||x>=m||y>=n||grid[x][y]==1)
continue;
queue.add(new int[]{x,y,p[2]+1});
}
}
return -1;
}
}

127. 单词接龙

class Solution {
public int ladderLength(String d, String endWord, List<String> wordList) {
int ans = 0;
if(wordList.size()==0) return ans;
LinkedList<String> queue = new LinkedList<>();
boolean[] visited = new boolean[wordList.size()];
queue.add(d);
while(!queue.isEmpty()) {
int size = queue.size();
ans++;
while(size-->0) {
String p = queue.poll();
for(int i = 0; i < wordList.size(); i++) {
String s = wordList.get(i);
if(!visited[i] && f(p,s)) {
if(s.equals(endWord)) return ++ans;
queue.add(s);
visited[i] = true;
}
}
}
}
return 0;
}
private boolean f(String s1, String s2) {
int i = 0;
int j = 0;
boolean flag = true;
while(i < s1.length()) {
if(s1.charAt(i) == s2.charAt(j)) {
i++;
j++;
}else if(s1.charAt(i) != s2.charAt(j)&&flag) {
flag = false;
i++;
j++;
}else return false;
}
return true;
}
}

二、DFS

解决的问题:用来解决连通性的问题。

在程序实现 DFS 时需要考虑以下问题:

  • 栈:用栈来保存当前节点信息,当遍历新节点返回时能够继续遍历当前节点。可以使用递归栈。
  • 标记:和 BFS 一样同样需要对已经遍历过的节点进行标记。
  • 判断:进栈出栈都需要判断元素是否已经被访问过,因为栈中有可能出现已经访问过的元素(找个图自己走一下)。

695. 岛屿的最大面积

import javafx.util.Pair;
class Solution {
public int maxAreaOfIsland(int[][] grid) {
int[][] direction = {{-1,0},{1,0},{0,-1},{0,1}};
int ans = 0;
for(int i = 0; i < grid.length; i++) {
for(int j = 0; j < grid[0].length; j++) {
if(grid[i][j]==1) {
int count = 0;
LinkedList<Pair<Integer,Integer>> queue = new LinkedList<>();
queue.add(new Pair<>(i,j));
while(!queue.isEmpty()) {
Pair<Integer,Integer> p = queue.pollLast();
if(grid[p.getKey()][p.getValue()]==1) {
count++;
grid[p.getKey()][p.getValue()] = 0;
for(int[] d : direction) {
int x = p.getKey() + d[0];
int y = p.getValue() + d[1];
if(x<0||y<0||x>=grid.length||y>=grid[0].length||grid[x][y]==0)
continue;
queue.add(new Pair<>(x,y));
}
}
}
ans = Math.max(ans,count);
}
}
}
return ans;
}
}

130. 被围绕的区域

import javafx.util.Pair;
class Solution {
public void solve(char[][] board) {
int[][] direction = {{-1,0},{1,0},{0,-1},{0,1}};
for(int i = 0; i < board.length; i++) {
for(int j = 0; j < board[0].length; j++) {
//边界O好处理一些,这里我们选择先找到边界O
if(board[i][j]=='O'&&(i==0||i==board.length-1||j==0||j==board[0].length-1)) {
LinkedList<Pair<Integer,Integer>> queue = new LinkedList<>();
queue.add(new Pair<>(i,j));
while(!queue.isEmpty()) {
Pair<Integer,Integer> p = queue.pollLast();
if(board[p.getKey()][p.getValue()]=='O') {
board[p.getKey()][p.getValue()] = 'T';
for(int[] d : direction) {
int x = p.getKey() + d[0];
int y = p.getValue() + d[1];
if(x<0||y<0||x>=board.length||y>=board[0].length||board[x][y]=='T'||board[x][y]=='X')
continue;
queue.add(new Pair<>(x,y));
}
}
}
}
}
}
for(int i = 0; i < board.length; i++) {
for(int j = 0; j < board[0].length; j++) {
if(board[i][j]=='O') board[i][j] = 'X';
if(board[i][j]=='T') board[i][j] = 'O';
}
}
}
}

417. 太平洋大西洋水流问题

class Solution {
public List<List<Integer>> pacificAtlantic(int[][] matrix) {
List<List<Integer>> ans = new LinkedList<>();
if(matrix.length == 0||matrix[0].length == 0) return ans;
int m = matrix.length;
int n = matrix[0].length;
boolean[][] m1 = new boolean[m][n];
boolean[][] m2 = new boolean[m][n];
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(i==0||j==0) dfs(matrix,new int[]{i,j},m1);
if(i==m-1||j==n-1) dfs(matrix,new int[]{i,j},m2);
}
}
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(m1[i][j]&&m2[i][j])
ans.add(Arrays.asList(i,j));
}
}
return ans;
}
private void dfs(int[][] matrix, int[] s, boolean[][] m) {
LinkedList<int[]> stack = new LinkedList<>();
int[][] dir = {{-1,0},{1,0},{0,-1},{0,1}};
stack.add(s);
while(!stack.isEmpty()) {
int[] p = stack.pollLast();
if(!m[p[0]][p[1]]) {
m[p[0]][p[1]] = true;
for(int[] d : dir) {
int x = p[0] + d[0];
int y = p[1] + d[1];
if(x<0||y<0||x>= matrix.length||y>=matrix[0].length||m[x][y])
continue;
if(matrix[x][y] >= matrix[p[0]][p[1]])
stack.add(new int[]{x,y});
}
}
}
}
}

三、回溯

解决的问题:排列组合问题。

回溯法其实就是一种枚举,把所有的情况都走一遍筛选出符合条件的解。有很多的题都可以用回溯解决,但是效率相差很大。回溯法适合解决,枚举出100种情况,但是有98种情况符合题意的这类问题。但是,如果枚举100种情况,只有1种情况符合题意,显示用回溯效率是极低。

因为 Backtracking 不是立即返回,而要继续求解,因此在程序实现时,需要注意对元素的标记问题:

  • 在访问一个新元素进入新的递归调用时,需要将新元素标记为已经访问,这样才能在继续递归调用时不用重复访问该元素;
  • 但是在递归返回时,需要将元素标记为未访问,因为只需要保证在一个递归链中不同时访问一个元素,可以访问已经访问过但是不在当前递归链中的元素。

17. 电话号码的字母组合

class Solution {
private HashMap<Integer,String> hash = new HashMap<>();
private LinkedList<String> ans = new LinkedList<>();
public List<String> letterCombinations(String digits) {
hash.put(2,"abc");
hash.put(3,"def");
hash.put(4,"ghi");
hash.put(5,"jkl");
hash.put(6,"mno");
hash.put(7,"pqrs");
hash.put(8,"tuv");
hash.put(9,"wxyz");
if(digits == null || digits.length() == 0) return ans;
backtrace("",digits);
return ans;
}
private void backtrace(String temp, String digits) {
if(digits.length()==0) {
ans.add(temp);
}else {
Integer key = Integer.valueOf(digits.substring(0,1));
String s = hash.get(key);
for(int i = 0; i < s.length(); i++) {
temp = temp + s.substring(i,i+1);
backtrace(temp,digits.substring(1));
temp = temp.substring(0,temp.length()-1);
}
}
}
}

93. 复原IP地址

class Solution {
List<String> ans = new LinkedList<>();
public List<String> restoreIpAddresses(String s) {
backtrace(0,s,"");
return ans;
}
private void backtrace(int k, String s, String temp) {
if(k==4||s.length()==0) {
if(k==4&&s.length()==0) ans.add(temp);
return;
}else {
for(int i = 0;i < s.length() &&i <= 2; i++) {
if(s.charAt(0)=='0'&&i!=0) break;
String part = s.substring(0,i+1);
if(Integer.valueOf(part)<=255) {
if(temp.length()!=0) {
part = '.' + part;
}
temp = temp + part;
backtrace(k+1,s.substring(i+1),temp);
temp = temp.substring(0,temp.length()-part.length());
}
}
}
}
}

37. 解数独

class Solution {
private boolean[][] m = new boolean[9][10];
private boolean[][] n = new boolean[9][10];
private boolean[][] k = new boolean[9][10];
private char[][] b;
public void solveSudoku(char[][] board) {
b = board;
for(int i = 0; i < 9; i++) {
for(int j = 0; j < 9; j++) {
if(board[i][j]!='.') {
int num = board[i][j] - '0';
m[i][num] = true;
n[j][num] = true;
k[(i/3)*3+j/3][num] = true;
}
}
}
backtrace(0,0);
}
private boolean backtrace(int r, int c) {
if(r < 8 && c == 9) {
r++;
c = 0;
}
if(r == 8 && c == 9) return true;
if(b[r][c] == '.') {
for(int i = 1; i <= 9; i++) {
int x = (r/3)*3+c/3;
if(m[r][i]||n[c][i]||k[x][i]) continue;
b[r][c] = (char)('0'+i);
m[r][i] = true;
n[c][i] = true;
k[x][i] = true;
if(backtrace(r,c+1)) return true;
b[r][c] = '.';
m[r][i] = false;
n[c][i] = false;
k[x][i] = false;
}
}else return backtrace(r,c+1);
return false;
}
}

51. N皇后

class Solution {
List<List<String>> list = new LinkedList<>();
public List<List<String>> solveNQueens(int n) {
boolean[] c = new boolean[n+1];
boolean[][] b = new boolean[n+1][n+1];
backtrace(1,n,c,b);
return list;
}
private void backtrace(int k, int n, boolean[] c, boolean[][] b) {
if(k == n+1) {
fill(b,n);
return;
}
for(int i = 1; i <= n; i++) {
if(c[i]||isHou(k,i,n,b)) continue;
b[k][i] = true;
c[i] = true;
backtrace(k+1,n,c,b);
b[k][i] = false;
c[i] = false;
}
}
private void fill(boolean[][] b, int n) {
LinkedList<String> temp = new LinkedList<>();
for(int i = 1; i <= n; i++) {
StringBuilder s = new StringBuilder();
for(int j = 1; j <= n; j++) {
if(b[i][j]) s.append('Q');
else s.append('.');
}
temp.add(new String(s));
}
list.add(temp);
}
private boolean isHou(int x, int y, int n, boolean[][] b) {
int i = x;
int j = y;
while(i<=n&&j<=n) {
if(b[i++][j++]) return true;
}
i = x;
j = y;
while(i>=1&&j>=1) {
if(b[i--][j--]) return true;
}
i = x;
j = y;
while(i>=1&&j<=n) {
if(b[i--][j++]) return true;
}
i = x;
j = y;
while(i<=n&&j>=1) {
if(b[i++][j--]) return true;
}
return false;
}
}

搜索(BFS、DFS、回溯)的更多相关文章

  1. 搜索入门_简单搜索bfs dfs大杂烩

    dfs题大杂烩 棋盘问题  POJ - 1321 和经典的八皇后问题一样.  给你一个棋盘,只有#区域可以放棋子,同时同一行和同一列只能有一个棋子. 问你放k个棋子有多少种方案. 很明显,这是搜索题. ...

  2. hdu 4771 Stealing Harry Potter's Precious (2013亚洲区杭州现场赛)(搜索 bfs + dfs) 带权值的路径

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4771 题目意思:'@'  表示的是起点,'#' 表示的是障碍物不能通过,'.'  表示的是路能通过的: ...

  3. 利用广度优先搜索(BFS)与深度优先搜索(DFS)实现岛屿个数的问题(java)

    需要说明一点,要成功运行本贴代码,需要重新复制我第一篇随笔<简单的循环队列>代码(版本有更新). 进入今天的主题. 今天这篇文章主要探讨广度优先搜索(BFS)结合队列和深度优先搜索(DFS ...

  4. 深度优先搜索(DFS)和广度优先搜索(BFS)求解迷宫问题

    用下面这个简单的迷宫图作为例子: OXXXXXXX OOOOOXXX XOXXOOOX XOXXOXXO XOXXXXXX XOXXOOOX XOOOOXOO XXXXXXXO O为通路,X为障碍物. ...

  5. LeetCode刷题总结-DFS、BFS和回溯法篇

    本文总结LeetCode上有关深度优先搜索(DFS).广度优先搜索(BFS)和回溯法的算法题,推荐刷题总数为13道.具体考点分析如下图: 一.深度优先搜索 1.字符匹配问题 题号:301. 删除无效的 ...

  6. 深度优先搜索DFS和广度优先搜索BFS简单解析(新手向)

    深度优先搜索DFS和广度优先搜索BFS简单解析 与树的遍历类似,图的遍历要求从某一点出发,每个点仅被访问一次,这个过程就是图的遍历.图的遍历常用的有深度优先搜索和广度优先搜索,这两者对于有向图和无向图 ...

  7. 深度优先搜索(DFS)与广度优先搜索(BFS)的Java实现

    1.基础部分 在图中实现最基本的操作之一就是搜索从一个指定顶点可以到达哪些顶点,比如从武汉出发的高铁可以到达哪些城市,一些城市可以直达,一些城市不能直达.现在有一份全国高铁模拟图,要从某个城市(顶点) ...

  8. 深度优先搜索(DFS)和广度优先搜索(BFS)

    深度优先搜索(DFS) 广度优先搜索(BFS) 1.介绍 广度优先搜索(BFS)是图的另一种遍历方式,与DFS相对,是以广度优先进行搜索.简言之就是先访问图的顶点,然后广度优先访问其邻接点,然后再依次 ...

  9. 深度优先搜索DFS和广度优先搜索BFS简单解析

    转自:https://www.cnblogs.com/FZfangzheng/p/8529132.html 深度优先搜索DFS和广度优先搜索BFS简单解析 与树的遍历类似,图的遍历要求从某一点出发,每 ...

  10. [LeetCode] 79. 单词搜索(DFS,回溯)

    题目 给定一个二维网格和一个单词,找出该单词是否存在于网格中. 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中"相邻"单元格是那些水平相邻或垂直相邻的单元格.同一个单元格 ...

随机推荐

  1. java 内部类简单总结

    在java中,一个类可以放在另一个类的内部,称之为内部类,相对而言,包含它的类称之为外部类.不过对于Java虚拟机而言,它是不知道内部类这回事的, 每个内部类最后都会被编译为一个独立的类,生成一个独立 ...

  2. idea快捷方式2

    IntelliJ Idea 常用快捷键列表 Ctrl+Shift + Enter,语句完成“!”,否定完成,输入表达式时按 “!”键Ctrl+E,最近的文件Ctrl+Shift+E,最近更改的文件Sh ...

  3. Maven项目转化出WebContent风格的目录

    这篇文章已被废弃. 现在,Deolin已经比较熟悉Maven,完全可以使用Jetty插件调试.热部署项目了. 在 [SpringMVC框架下Web项目的搭建与部署] 中,提到了将tomcat的默认上下 ...

  4. Docker实践--搭建Yapi测试平台

    背景:项目需要选择不同测试平台,筛选一个最佳平台 现状:一台机器安装多套环境,虚拟机太繁琐 解决方案:通过Docker模拟安装测环境 参考:https://blog.csdn.net/qq_32447 ...

  5. 下板不动, 上板匀速平板间流动(c++)【转载】

    摘自<FLUENT流体工程仿真计算实例与分析>,程序略有修改 两个间距为1cm水平平板,如下图所示: 上板匀速平板间流动(c++)[转载]" title="下板不动,  ...

  6. Python generator 类型

    场景: 使用gurobi求解优化问题时,遇到quicksum()函数用法如下: quicksum(mu[i] for i in range(n)) 读着很流畅而且好像并没什么问题欸,但 mu[i] f ...

  7. SQL-W3School-高级:SQL CREATE TABLE 语句

    ylbtech-SQL-W3School-高级:SQL CREATE TABLE 语句 1.返回顶部 1. CREATE TABLE 语句 CREATE TABLE 语句用于创建数据库中的表. SQL ...

  8. SQL-W3School-高级:SQL JOIN

    ylbtech-SQL-W3School-高级:SQL JOIN 1.返回顶部 1. SQL join 用于根据两个或多个表中的列之间的关系,从这些表中查询数据. Join 和 Key 有时为了得到完 ...

  9. kotlin委托属性

    fun main(arg: Array<String>) { val myClass1 = myClass1() myClass1.name="mycalsss1" v ...

  10. 【工具】sqlmap 中文手册 使用教程

    日期:2019-07-28 09:27:27 更新: 作者:Bay0net 介绍:自己翻译了一下,做个备忘. 0x01. 基本信息 官网 sqlmap: automatic SQL injection ...