def BFS(graph, start, end):
visited = set()
queue = []
queue.append([start])
while queue:
node = queue.pop()
visited.add(node)
process(node)
nodes = generate_related_nodes(node)
queue.push(nodes)
# other processing work
...
visited = set()
def dfs(node, visited):
if node in visited: # terminator
# already visited
return
visited.add(node)
# process current node here.
...
for next_node in node.children():
if next_node not in visited:
dfs(next_node, visited)
def DFS(self, tree):
if tree.root is None:
return []
visited, stack = [], [tree.root]
while stack:
node = stack.pop()
visited.add(node)
process (node)
nodes = generate_related_nodes(node)
stack.push(nodes)
# other processing work
...
BFS解法
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
if (root == null) return new ArrayList<>();
LinkedList<TreeNode> queue = new LinkedList<>();
List<List<Integer>> res = new ArrayList<>();
queue.offerLast(root);
while (!queue.isEmpty()) {
int size = queue.size();
List<Integer> tmpList = new ArrayList<>();
for (int i = 0; i < size; i++) {
TreeNode cur = queue.pollFirst();
tmpList.add(cur.val);
if (cur.left != null) queue.offerLast(cur.left);
if (cur.right != null) queue.offerLast(cur.right);
}
res.add(tmpList);
}
return res;
}
}
虽然是经典的BFS题目,但是用DFS也可以做出来
DFS解法
public class Solution {
List<List<Integer>> res;
public List<List<Integer>> levelOrder(TreeNode root) {
if (root == null) return new LinkedList<>();
res = new LinkedList<>();
dfs(root, 0);
return res;
}
private void dfs(TreeNode root, int depth) {
if (root == null) return;
if (depth >= res.size()) res.add(new LinkedList<>());
res.get(depth).add(root.val);
dfs(root.left, depth + 1);
dfs(root.right, depth + 1);
}
}
public class Solution {
List<String> res;
int n;
public List<String> generateParenthesis(int n) {
res = new ArrayList<>();
this.n = n;
dfs(0, 0, "");
return res;
}
/**
* @param left 左括号个数
* @param right 右括号个数
* @param s 结果字符串
*/
private void dfs(int left, int right, String s) {
//退出条件
if (left == n && right == n) {
res.add(s);
return;
}
//可以生成左括号的条件:左括号小于n
if (left < n) dfs(left + 1, right, s + "(");
//可以生成右括号的条件:右括号小于左括号
if (left > right) dfs(left, right + 1, s + ")");
//reserve
}
}
和二叉树的中序遍历做法几乎一模一样,只需要修改结果集产生的方式
BFS解法
public class Solution {
public List<Integer> largestValues(TreeNode root) {
if (root == null) return new ArrayList<>();
List<Integer> res = new ArrayList<>();
Deque<TreeNode> deque = new LinkedList<TreeNode>();
deque.offerLast(root);
while (!deque.isEmpty()) {
int size = deque.size();
int lineMax = Integer.MIN_VALUE;
for (int i = 0; i < size; i++) {
TreeNode cur = deque.pollFirst();
lineMax = Math.max(lineMax, cur.val);
if (cur.left != null) deque.offerLast(cur.left);
if (cur.right != null) deque.offerLast(cur.right);
}
res.add(lineMax);
}
return res;
}
}
遍历二维数组,当发现1之后,计数+1,然后调用函数dfs
递归的去将这个1的所有邻接的1都变为0,然后继续搜索
public class Solution {
public int numIslands(char[][] grid) {
if (grid == null || grid.length == 0 || grid[0].length == 0) return 0;
int count = 0;
int rows = grid.length;
int cols = grid[0].length;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (grid[r][c] == '1') {
count++;
//发现岛屿,然后广度优先搜索临界的区域,全部变成海洋
dfs(r, c, rows, cols, grid);
}
}
}
return count;
}
private void dfs(int r, int c, int rows, int cols, char[][] grid) {
if (r == -1 || c == -1 || r == rows || c == cols || grid[r][c] != '1') return;
//将当前1标记为0
grid[r][c] = 0;
//向上左右进行扩展
dfs(r + 1, c, rows, cols, grid);
dfs(r - 1, c, rows, cols, grid);
dfs(r, c + 1, rows, cols, grid);
dfs(r, c - 1, rows, cols, grid);
}
}
BFS解法
public class Solution {
public int numIslands(char[][] grid) {
if (grid == null || grid.length == 0 || grid[0].length == 0) return 0;
int count = 0;
int rows = grid.length;
int cols = grid[0].length;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (grid[r][c] == '1') {
count++;
//发现岛屿,然后广度优先搜索临界的区域,全部变成海洋
bfs(r, c, rows, cols, grid);
}
}
}
return count;
}
private void bfs(int r, int c, int rows, int cols, char[][] grid) {
Deque<Integer> deque = new LinkedList<>();
//将二维数组换为一维进行存储
deque.offer(r * cols + c);
while (!deque.isEmpty()) {
Integer cur = deque.poll();
int row = cur / cols;
int col = cur % cols;
//如果已经遍历过了,就不再重复
if (grid[row][col] == '0') {
continue;
}
grid[row][col] = '0';
if (row != (rows - 1) && grid[row + 1][col] == '1') {
deque.offer((row + 1) * cols + col);
}
if (col != (cols - 1) && grid[row][col + 1] == '1') {
deque.offer(row * cols + col + 1);
}
if (row != 0 && grid[row - 1][col] == '1') {
deque.offer((row - 1) * cols + col);
}
if (col != 0 && grid[row][col - 1] == '1') {
deque.offer(row * cols + col - 1);
}
}
}
}
解决方案和上一个题岛屿数量一致,遍历整个数组,发现1之后,采用dfs或者bfs进行沉岛
DFS解法
public class Solution {
public int maxAreaOfIsland(int[][] grid) {
if (grid == null || grid.length == 0 || grid[0].length == 0) return 0;
int maxSize = 0;
int rows = grid.length;
int cols = grid[0].length;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (grid[r][c] == 1) {
maxSize = Math.max(maxSize, dfs(r, c, rows, cols, grid));
}
}
}
return maxSize;
}
private Integer dfs(int r, int c, int rows, int cols, int[][] grid) {
if (r == -1 || c == -1 || r == rows || c == cols || grid[r][c] == 0) {
return 0;
}
//将访问过的岛屿弄成0
grid[r][c] = 0;
int num = 1;
//每个方向都进行遍历,遍历的结果进行累加就是最终的面积
num += dfs(r + 1, c, rows, cols, grid);
num += dfs(r, c + 1, rows, cols, grid);
num += dfs(r - 1, c, rows, cols, grid);
num += dfs(r, c - 1, rows, cols, grid);
return num;
}
}
DFS解法
public class Solution {
public void solve(char[][] board) {
if (board == null || board.length == 0 || board[0].length == 0) return;
int m = board.length;
int n = board[0].length;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
boolean isEdge = i == 0 || j == 0 || i == m - 1 || j == n - 1;
if (isEdge && board[i][j] == 'O')
dfs(board, i, j);
}
}
//将与边界'O'有段的'O'标记之后
//将‘O’转换为‘X’
//将‘#’转换为‘O’
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (board[i][j] == 'O') board[i][j] = 'X';
if (board[i][j] == '#') board[i][j] = 'O';
}
}
}
private void dfs(char[][] board, int i, int j) {
if (i == -1 || j == -1
|| i == board.length || j == board[0].length
|| board[i][j] == 'X' || board[i][j] == '#') {
return;
}
//将边界‘O’和与边界‘O’相邻的‘O’都设置为#
board[i][j] = '#';
dfs(board, i - 1, j);
dfs(board, i + 1, j);
dfs(board, i, j - 1);
dfs(board, i, j + 1);
}
}
用一个boolean数组记录字典中的字符串是否被访问过了
标准的bfs遍历模板(和二叉树的层次遍历相似),只是加上了一些条件的判断
public class Solution {
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
if (!wordList.contains(endWord)) {
return 0;
}
//记录是否访问过
boolean[] visited = new boolean[wordList.size()];
//检验是否存在beginWord,如果存在,就置为访问过了,没必要访问
int index = wordList.indexOf(beginWord);
if (index != -1) {
visited[index] = true;
}
//bfs暂存队列
Queue<String> queue = new LinkedList<>();
queue.offer(beginWord);
int count = 0;
while (!queue.isEmpty()) {
int size = queue.size();
count++;
while (size-- > 0) {
String start = queue.poll();
for (int i = 0; i < wordList.size(); i++) {
//访问过了,跳过,访问下一个
if (visited[i]) continue;
String s = wordList.get(i);
//不满足和当前只差一个字符不同,跳过,访问下一个
if (!canConvert(start, s)) {
continue;
}
//和endWord匹配上了,进行返回,因为是bfs,所以找到了直接返回就是最短的
if (s.equals(endWord)) {
return count + 1;
}
//访问完了将当前置为已访问
visited[i] = true;
//当前值压栈
queue.offer(s);
}
}
}
return 0;
}
//判断s1和s2是否只有一个字符不同
private boolean canConvert(String s1, String s2) {
int count = 0;
for (int i = 0; i < s1.length(); i++) {
if (s1.charAt(i) != s2.charAt(i)) {
count++;
if (count > 1) {
//达到两个不同了,说明不符合
return false;
}
}
}
//不同字符小于两个,判断是否是一个
return count == 1;
}
}
BFS解法2:双向BFS
public class Solution {
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
int end = wordList.indexOf(endWord);
if (end == -1) return 0;
wordList.add(beginWord);
int start = wordList.size() - 1;
//bfs暂存队列
Queue<Integer> queue1 = new LinkedList<>();
Queue<Integer> queue2 = new LinkedList<>();
//访问记录set
Set<Integer> visited1 = new HashSet<>();
Set<Integer> visited2 = new HashSet<>();
queue1.offer(start);
queue2.offer(end);
visited1.add(start);
visited2.add(end);
int count = 0;
while (!queue1.isEmpty() && !queue2.isEmpty()) {
count++;
//判断两个队列的长度,把短的令成1,然后把短的进行遍历,加快速度
if (queue1.size() > queue2.size()) {
//将两个的队列和set都交换下
Queue<Integer> tmpqueue = queue1;
queue1 = queue2;
queue2 = tmpqueue;
Set<Integer> tmpset = visited1;
visited1 = visited2;
visited2 = tmpset;
}
int size = queue1.size();
while (size-- > 0) {
String s = wordList.get(queue1.poll());
for (int i = 0; i < wordList.size(); i++) {
//访问过了,跳过,访问下一个
if (visited1.contains(i)) continue;
//不满足和当前只差一个字符不同,跳过,访问下一个
if (!canConvert(s, wordList.get(i))) {
continue;
}
//退出条件
if (visited2.contains(i)) {
return count + 1;
}
//访问完了将当前置为已访问
visited1.add(i);
//当前值压栈
queue1.offer(i);
}
}
}
return 0;
}
//判断s1和s2是否只有一个字符不同
private boolean canConvert(String s1, String s2) {
int count = 0;
for (int i = 0; i < s1.length(); i++) {
if (s1.charAt(i) != s2.charAt(i)) {
if (++count > 1) {
//达到两个不同了,说明不符合
return false;
}
}
}
//不同字符小于两个,判断是否是一个
return count == 1;
}
}