什么是深度优先搜索
深度优先搜索算法(英语:Depth-First-Search,DFS)是一种用于遍历或搜索树或图的算法。其过程简单来说就是对每一个可能的分支深入到不能再深入位置,而且每个节点只能访问一次。
算法题应用场景
1.二叉树有关问题
2.需要从根节点遍历到末尾子节点
3.遍历图
常见题型
深度优先搜索的二叉树模板
// 深度优先搜索模板
function dfsSearch() {
// 初始化当前结果
let start, currentResult
// 递归函数
let dfs = function (node, currentResult) {
if (!node) { return null }
// 更新当前结果currentResult
// 若到达末尾叶子节点,进行最优结果更新
if (node.left == null && node.right == null) {
// 更新最优结果
}
// 左右子树递归
dfs(node.left, currentResult)
dfs(node.right, currentResult)
}
dfs(root, start)
return currentResult
}
判断是否是二叉搜索树
二叉树的中序遍历正好满足二叉搜索树的从小到大的排列规则
const helper = (root, lower, upper) => {
if (root === null) {
return true;
}
if (root.val <= lower || root.val >= upper) {
return false;
}
return helper(root.left, lower, root.val) && helper(root.right, root.val, upper);
}
var isValidBST = function(root) {
return helper(root, -Infinity, Infinity);
};
对无向图的深度优先搜索
- 获取二维数组的长宽
- 遍历并添加边界条件递归调用DFS函数
-
机器人行走范围
对无向图的深度优先搜索模板(岛屿数量)
function get(arr) {
// 通常输入的数组都是二维数组
let m = arr.length
let n = arr[0].length
let count = 0
function dfs(i, j) {
// 跳出递归的边界条件
if (i < 0 || j < 0 || i >= m || j >= n) return
// 按照题中所给的要求递归遍历无向图
dfs(i - 1, j) || dfs(i + 1, j) || dfs(i, j - 1) || dfs(i, j + 1)
}
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
// 符合题目的条件添加进结果或者计数
if (arr[i][j] == 1) {
// 更细最新结果
count++
dfs(i, j)
}
}
}
return count
}
图像渲染
var floodFill = function (image, sr, sc, newColor) {
let m = image.length
let n = image[0].length
let oldColor = image[sr][sc]
if (newColor == oldColor) {
return image
}
let dfs = function (i, j) {
if (i < 0 || j < 0 || i >= m || j >= n || image[i][j] !== oldColor) {
return
}
image[i][j] = newColor
dfs(i + 1, j) || dfs(i, j + 1) || dfs(i, j - 1) || dfs(i - 1, j)
}
dfs(sr, sc)
return image
};
深拷贝的深度优先搜索
不需要创建函数的DFS
路径总和
:::tips 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。
叶子节点 是指没有子节点的节点。 :::
:::tips
输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
输出:true
解释:等于目标和的根节点到叶节点路径如上图所示。
:::
:::tips
输入:root = [1,2,3], targetSum = 5
输出:false
解释:树中存在两条根节点到叶子节点的路径:
(1 —> 2): 和为 3
(1 —> 3): 和为 4
不存在 sum = 5 的根节点到叶子节点的路径。
:::
:::tips
输入:root = [], targetSum = 0
输出:false
解释:由于树是空的,所以不存在根节点到叶子节点的路径。
:::
var hasPathSum = function(root, targetSum) {
if(root === null) {
return false
}
// 搜到叶子节点,则判断当前节点值是否等于目标值
if(root.left === null && root.right === null) {
return root.val === targetSum
}
// 还没搜到叶子节点,则进行 目标值-当前节点值,并继续往下搜
return hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val)
};
路径总和ii
输出全部满足的路径数组
/**
* @param {TreeNode} root
* @param {number} targetSum
* @return {number[][]}
*/
var pathSum = function (root, targetSum) {
let res = [];
let path = [];
const dfs = (root, targetSum) => {
// 如果节点为空则不需要再递归了
if (root == null) {
return;
}
// 把当前节点的值加入路径中
path.push(root.val);
// 由于路径中加入了当前节点,那目标值就少了
targetSum -= root.val;
if (root.left == null && root.right == null && targetSum == 0) {
// 如果到达叶子节点 并且目标值满足
res.push(path.slice());
// res.push(path.concat());
}
dfs(root.left, targetSum);
dfs(root.right, targetSum);
// 左右子节点都递归完了,把当前节点从路径中删除,可走下一条路径
path.pop();
};
dfs(root, targetSum);
return res;
};
路径总和iii
var sumNumbers = function (root) {
return dfs(root, 0)
};
let dfs = function (root, prevSum) {
if (!root) {
return 0
}
let sum = prevSum * 10 + root.val
if (!root.left && !root.right) {
return sum
}
return dfs(root.left, sum) + dfs(root.right, sum)
}
判断两个二叉树是否相等
var isSameTree = function(p, q) {
if(!p && !q)
return true;
if(!p || !q)
return false;
if(p.val != q.val)
return false;
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
单词搜索
var exist = function(board, word) {
const W = board.length;
const H = board[0].length
const K = word.length
//搜索的方向
const dirs = [[0, -1], [1, 0],[0, 1],[-1, 0]]
function helper(i, j, k) {
if (k>=K) return true
if (i >= W || j >= H || i < 0 || j < 0) return false
if (board[i][j] !== word[k]) return false
board[i][j]='*'
for (let [x,y] of dirs) {
if(helper(i+x,j+y,k+1)) return true
}
board[i][j]=word[k]
return false
}
for (let i = 0; i < W; i++) {
for (let j = 0; j < H; j++) {
if (helper(i,j,0)) return true
}
}
return false
};