哈喽,又到了一周一打卡的时间了,肝了两天,算是弄懂了一丢丢的BFS&&DFS
先介绍一下 广度优先搜索算法 Breadth First Search (BFS),初步了解,其实有点像二叉树问题中用到的层序遍历时 使用队列结构来辅助实现解决问题, 广度优先,顾名思义是广,其重点就是在同一层中进行查找是否有符合解决问题的答案,一层处理完再到下一层中去
BFS相关题目
542. 01 矩阵
该题的意思就是将所有为0的格子到非0的格子所需要的走到格子数记录到该非0格子中
var updateMatrix = function(mat) {
let cols = mat[0].length; // 列
let rows = mat.length; // 行
// 结果集
let dist = new Array(rows).fill(0).map(() => new Array(cols).fill(0));
// 记录每个格子的状态
let vis = new Array(rows).fill(false).map(() => new Array(cols).fill(false));
// 当前格子可移动方向的坐标
let pos = [
[0,1],
[0,-1],
[1,0],
[-1,0]
]
// BFS实现所需的队列
let quene = []
// 对每个格子进行vis初始化
for(let i = 0; i < rows; i++){
for(let j = 0; j < cols; j++){
if(mat[i][j] === 0){
quene.push([i,j])
vis[i][j] = true
}
}
}
while(quene.length){
let [x,y] = quene.shift()
// 通过格子可移动方向计算结果集中对应格子的步数
for(let [i,j] of pos){
let newX = x + i
let newY = y + j
if( newX < 0 ||
newY < 0 ||
newX >= rows ||
newY >= cols ||
vis[newX][newY]){
continue;
}
dist[newX][newY] = dist[x][y] + 1
vis[newX][newY] = true
quene.push([newX,newY])
}
}
return dist
};
752. 打开转盘锁
这题的意思就是在deadends中的字符串数字中是被锁住的,无法进行旋转 那这里的旋转的意思就是 如果当前数字是0 那就向上旋转为9 即 0 + 9 如果当前数字是 9 即向下旋转为 0 即 9 + 1 取模 为 0, 然后每旋转一次就记录一次,最后求出最小的旋转数, 那这里需要用到Set 的不会重复存储的特性,方便解题
var openLock = function(deadends, target) {
let step = 0 // 步数
let deadSet = new Set() // 存储无法旋转的字符串数字
let vistSet = new Set() // 存储已经旋转存在过的数字
for(let num of deadends){
deadSet.add(num)
}
let quene = ['0000'] // 题目要求从0000开始旋转
while(quene.length){
let size = quene.length;
while(size--){
let val = quene.shift()
if(val === target ){
return step
}
if(deadSet.has(val) || vistSet.has(val)){
continue;
}
vistSet.add(val)
for(let j = 0; j < val.length; j++){
let num = val[j] - '0'
// 求出当前旋转后的数字
let up = (num + 1) % 10,
dowm = (num + 9 )% 10
// 拼接后push到队列中
quene.push(val.substring(0,j) + up + val.substring(j+1))
quene.push(val.substring(0,j) + dowm + val.substring(j+1))
}
}
step++
}
return -1
};
1091. 二进制矩阵中的最短路径
该题就是说 在正方形的宫格中从0,0出发 分别可以在横纵对角线的方向进行前进,但途经为0的格子,求改路径途径的格子总数
var shortestPathBinaryMatrix = function(grid) {
let depth = 0;
// 是一个正方形
let m = grid.length - 1;
// 边界情况,如果开头或结尾是1的情况下,不论怎么走都不可能达到题目要求
if (grid[0][0] == 1 || grid[m][m] == 1) return -1;
// 如果只有一个元素的情况
if (m == 0) return 1;
let queue = [[0, 0]];
grid[0][0] = 1
// 由于增加了对角线的方向,那么固定走向坐标为8个
let pos = [
[0,-1],
[0,1],
[-1,0],
[1,0],
[-1,-1],
[-1,1],
[1,-1],
[1,1],
]
while(queue.length){
depth++
let size = queue.length
console.log(queue)
while(size--){
let [curX,curY] = queue.shift()
// 如果当前坐标等于m了 那说明到最后了,返回结果即可
if (curX == m && curY == m) return depth;
for(let [x,y] of pos){
let newX = curX + x, newY = curY + y
if(
newX > m ||
newY > m ||
newX < 0 ||
newY < 0 ||
grid[newX][newY] == 1
){
continue
}
queue.push([newX,newY])
grid[newX][newY] = 1
}
}
}
return -1
};
到了深度优先搜索算法 Depth First Search(DFS), 我草率的理解就是不断的递归,分各种条件去递归
DFS相关题目
130. 被围绕的区域
该题就是将宫格中被X围绕的O 改为X,这里我采取的就是先将为大O的记录为小o,最后将小o记录为大O,大O全部改为X, 最先要处理的是四边的O因为四边的O肯定没有被X包围的,所以可以直接处理
var solve = function(board) {
// 创建二维数组,默认全部置0
let m=board.length, n=board[0].length
let dir = [
[0,1],
[0,-1],
[1,0],
[-1,0]
]
let dfs = (i, j, arr) => {
arr[i][j] = 'o'
for(let [x,y] of dir) {
let newX = x + i, newY = y + j;
if( newX < 0 ||
newY < 0 ||
newX >= m ||
newY >= n ||
arr[newX][newY] != 'O'
){
continue;
}
dfs(newX, newY, arr)
}
}
// 处理左右两边的O
for(let i = 0; i < m; i++){
if(board[i][0] === 'O' ){
dfs(i, 0, board);
}
if(board[i][n-1] === 'O'){
dfs(i, n-1, board)
}
}
// 处理上下两边的O
for(let i = 0; i < n; i++){
if(board[0][i] === 'O' ){
dfs(0, i, board);
}
if(board[m-1][i] === 'O'){
dfs(m-1, i, board)
}
}
// 将大O改为X 小o改为O
for(let i = 0; i < m; i++){
for(let j = 0; j < n; j++){
if(board[i][j] == 'O'){
board[i][j] = 'X'
}
if(board[i][j] == 'o'){
board[i][j] = 'O'
}
}
}
};
473. 火柴拼正方形
这题,就是说用题目给的火柴棍来拼成正方形,但是给的火柴长度不等,数量也不等,这里桶这么一个解题思路,由于是正方形,那么四边就是相等的,那就是说我可以用4个大小相同的桶来表示火柴衔接起来的长度,如果长度都刚好能表示桶的大小,那直接返回true即可,但是会出现桶只有3的大小,那火柴是长度2的大小,就会出现填不满问题,就是可能会有余量大于最小火柴的长度,这里采取剪枝的方式
let dfs = function(index, arr, ms) {
if (index == -1 ) return true
for(let i = 0; i < 4; i++) {
if (arr[i] < ms[index]) continue
if (arr[i] == ms[index] || arr[i] - ms[index] >= ms[0]) {
// 剪枝
arr[i] -= ms[index]
if (dfs(index - 1, arr, ms)) return true
arr[i] += ms[index]
}
}
return false
}
var makesquare = function(matchsticks) {
let sum = 0 // 总和
for(let item of matchsticks) sum += item
if (sum % 4) return false;
// 从小到大排序
matchsticks.sort((a, b) => a -b )
// 桶
let arr = new Array(4).fill(sum / 4)
// 从后往前搜索,先将大的往里塞
return dfs(matchsticks.length - 1, arr, matchsticks)
};