DFS深度优先搜索,递归模版
/*
* Return true if there is a path from cur to target.
*/
boolean DFS(Node cur, Node target, Set<Node> visited) {
return true if cur is target;
for (next : each neighbor of cur) {
if (next is not in visited) {
add next to visted;
return true if DFS(next, target, visited) == true;
}
}
return false;
}
1.岛屿数量
给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
题解思路:
在之前关于队列算法题文章中有采用广度优先搜索(BFS)该题的解法。而该题利用DFS思想解法为:首先遍历每个节点,同时通过DFS递归分别对附近(左上右下)的点进行访问,判断下一个要访问的节点为'1'时,将该点值置为'0'同时进一步深入遍历,当该节点附近节点都为'0'时则回溯到上一个点。直至该节点所有相邻为'1'的路径下的节点都被访问,并且都被置为'0’时,继续遍历下一个节点。
public static int numIslands(char[][] grid) {
int num = 0;
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
// 遍历每个节点
if (grid[i][j] == '1') {
// 节点为'1',岛屿数量+1,并递归访问所有相邻为'1'的节点,并将这些节点置为'1'
// 统一记作1个岛屿
num += 1;
grid[i][j] = '0';
dfs(i, j, grid);
}
}
}
return num;
}
public static void dfs(int i, int j, char[][] grid) {
// 分别访问左上右下值为'1'的节点
if (j - 1 >= 0 && grid[i][j - 1] == '1') {
// 访问时将节点置为'0'
grid[i][j - 1] = '0';
dfs(i, j - 1, grid);
}
if (i - 1 >= 0 && grid[i - 1][j] == '1') {
grid[i - 1][j] = '0';
dfs(i - 1, j, grid);
}
if (i + 1 < grid.length && grid[i + 1][j] == '1') {
grid[i + 1][j] = '0';
dfs(i + 1, j, grid);
}
if (j + 1 < grid[0].length && grid[i][j + 1] == '1') {
grid[i][j + 1] = '0';
dfs(i, j + 1, grid);
}
}
2.目标和
给定一个非负整数数组,a1, a2, ..., an, 和一个目标数,S。现在你有两个符号 + 和 -。对于数组中的任意一个整数,你都可以从 + 或 -中选择一个符号添加在前面。
返回可以使最终数组和为目标数 S 的所有添加符号的方法数
题解思路:
DFS递归方式:每个元素对应的操作符有“+-”两个,假设将0看作根节点,“+-”第一个元素看做“0”的左右两个子节点,则这两个子节点"+-"下一元素可看做下一级子节点(2个节点的分别左右4个节点)。依次类推,此时可将其看作是一个平衡二叉树,这时利用先序遍历以访问节点并采用节点对应的“+”或"-对应运算,运算到最后一个元素判断是否等于对应target值,如等于则方法数+1。
public int findTargetSumWays(int[] nums, int S) {
dfs2(nums, 0, 0, S);
return num;
}
static int num = 0;
public void dfs2(int[] nums, int i, int sum, int S) {
if (i == nums.length) {
if (sum == S)
num++;
return;
}
dfs2(nums, i + 1, sum + nums[i], S);
dfs2(nums, i + 1, sum - nums[i], S);
}
DFS显示栈模版代码
boolean DFS(int root, int target) {
Set<Node> visited;
Stack<Node> s;
add root to s;
while (s is not empty) {
Node cur = the top element in s;
return true if cur is target;
for (Node next : the neighbors of cur) {
if (next is not in visited) {
add next to s;
add next to visited;
}
}
remove cur from s;
}
return false;
}
3.二叉树的中序遍历(DFS显示栈,非递归方式)
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
while (root != null || !stack.isEmpty()) {
while (root != null) {
stack.push(root);
root = root.left;
}
root = stack.pop();
list.add(root.val);
root = root.right;
}
return list;
}
}
4.图像渲染
有一幅以二维整数数组表示的图画,每一个整数表示该图画的像素值大小,数值在 0 到 65535 之间。
给你一个坐标 (sr, sc) 表示图像渲染开始的像素值(行 ,列)和一个新的颜色值 newColor,让你重新上色这幅图像。
为了完成上色工作,从初始坐标开始,记录初始坐标的上下左右四个方向上像素值与初始坐标相同的相连像素点,接着再记录这四个方向上符合条件的像素点与他们对应四个方向上像素值与初始坐标相同的相连像素点,……,重复该过程。将所有有记录的像素点的颜色值改为新的颜色值。
最后返回经过上色渲染后的图像。
题解思路:
通“岛屿数量”一题思路相同,同样是通过DFS递归方式访问给定点相邻(上下左右)值相同的点,同时将该点数值改为新色值。
需要注意的是,当原始色值与新色值相同时,容易造成StackOverFlow错误,需要进行判断。
public int[][] floodFill(int[][] image, int sr, int sc, int newColor) {
int color = image[sr][sc];
// 当要修改的点颜色等于新颜色,直接返回
if(color == newColor) return image;
image[sr][sc] = newColor;
if (sr - 1 >= 0 && image[sr - 1][sc] == color) {
floodFill(image, sr - 1, sc, newColor);
image[sr - 1][sc] = newColor;
}
if (sr + 1 < image.length && image[sr + 1][sc] == color) {
floodFill(image, sr + 1, sc, newColor);
image[sr + 1][sc] = newColor;
}
if (sc - 1 >= 0 && image[sr][sc - 1] == color) {
floodFill(image, sr, sc - 1, newColor);
image[sr][sc - 1] = newColor;
}
if (sc + 1 < image[0].length && image[sr][sc + 1] == color) {
floodFill(image, sr, sc + 1, newColor);
image[sr][sc + 1] = newColor;
}
return image;
}