算法61天|图论
Posted 圆圆圈圈扁扁
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法61天|图论相关的知识,希望对你有一定的参考价值。
leetcode-master/图论广索理论基础.md at master · youngyangyang04/leetcode-master · GitHub
leetcode-master/图论深搜理论基础.md at master · youngyangyang04/leetcode-master · GitHub
1791. 找出星型图的中心节点
var findCenter = function(edges)
const n = edges.length + 1;
const degree = new Array(n+1).fill(0)
for(const edge of edges)
degree[edge[0]]++
degree[edge[1]]++
for(let i = 0;;i++)
if(degree[i] === n-1)
return i
;
统计各个节点的度,使用数组的方法统计,将节点的值当作数组的索引。然后有多一个的话,就++。会发现中间节点的度是n-1,其它的节点的度是1
tleetcode-master/1791.找出星型图的中心节点.md at master · youngyangyang04/leetcode-master · GitHub
797. 所有可能的路径
var allPathsSourceTarget = function(graph)
let result = []
let path = []
//x 是当前遍历的节点
// graph 是存当前的图
const dfs = function(path,graph,x)
// 终止条件
if(x === graph.length - 1)
//将结果加入
result.push([...path])
return
for(let i = 0;i<graph[x].length;i++)
//将节点加入
path.push(graph[x][i])
//dfs
dfs(path,graph,graph[x][i])
// 回溯
path.pop()
path.push(0)
dfs(path,graph,0)
return result
;
力扣
200. 岛屿数量
dfs
var numIslands = function (grid)
// 使用dfs
let dirx = [-1, 1, 0, 0]
let diry = [0, 0, -1, 1]
let row = grid.length
let col = grid[0].length
const dfs = function (grid, visited, i, j)
//终止条件
//for循环
for (let k = 0; k < 4; k++)
let x = i + dirx[k]
let y = j + diry[k]
if (x >= row || y >= col || x < 0 || y < 0)
continue
if (visited[x][y] === false && grid[x][y] === '1')
visited[x][y] = true
dfs(grid, visited, x, y)
let visited = new Array(grid.length).fill(false).map(() => new Array(grid[0].length).fill(false))
let count = 0
for (let i = 0; i < row; i++)
for (let j = 0; j < col; j++)
if (visited[i][j] === false && grid[i][j] === '1')
visited[i][j] === true
count++;
dfs(grid, visited, i, j)
return count
;
BFS
var numIslands = function (grid)
let dirx = [-1, 1, 0, 0]
let diry = [0, 0, -1, 1]
let row = grid.length
let col = grid[0].length
let visited = new Array(row).fill(false).map(() => new Array(col).fill(false))
// 先将节点加入队列中
const bfs = function (grid,visited,i,j)
let que = []
que.push([i, j])
visited[i][j] = true
while (que.length > 0)
// 弹出当前节点,获取当前元素的坐标
const [curx, cury] = que.shift()
//判断它上下左右有没有岛屿
for (let k = 0; k < 4; k++)
let x = curx + dirx[k]
let y = cury + diry[k]
if (x < 0 || y < 0 || x >= row || y >= col) continue
if (visited[x][y] != true && grid[x][y] === '1')
visited[x][y] = true
//加入节点
que.push([x, y])
let count = 0
for(let i = 0;i<row;i++)
for(let j = 0;j<col;j++)
if(visited[i][j] === false && grid[i][j] === '1')
count ++;
bfs(grid,visited,i,j)
return count
;
463. 岛屿的周长
如果碰到水域的话就+1,如果碰到边界也加1
var islandPerimeter = function(grid)
let row = grid.length
let col = grid[0].length
// i-1,j/i+1,j/i,j-1/i,j+1
let dirx = [-1,1,0,0]
let diry = [0,0,-1,1]
let count = 0
for(let i = 0;i<row;i++)
for(let j =0;j<col;j++)
if(grid[i][j] === 1)
for(let k=0;k<4;k++)
let x = i + dirx[k]
let y = j + diry[k]
if(x >= row ||
y >= col||
x < 0||
y<0||
grid[x][y] === 0)
count ++;
// 判断上下左右,如果遇到水域+1,如果遇到边界就+1
return count
;
695. 岛屿的最大面积
BFS
var maxAreaOfIsland = function (grid)
const bfs = function (grid, i, j, visited,count)
const dirx = [-1, 1, 0, 0]
const diry = [0, 0, -1, 1]
let que = []
visited[i][j] = true
que.push([i, j])
count ++
while (que.length > 0)
const [curx, cury] = que.shift()
for (let k = 0; k < 4; k++)
let newx = curx + dirx[k]
let newy = cury + diry[k]
if (newx < 0 || newy < 0|| newx >= row || newy >= col) continue
if (grid[newx][newy] === 1 && visited[newx][newy] !== true)
visited[newx][newy] = true
que.push([newx,newy])
count ++
return count
// 找到岛屿,找到的话,就数统计个数
let result = 0
// bfs
const col = grid[0].length
const row = grid.length
let visited = new Array(row).fill(false).map(() => new Array(col).fill(false))
for (let i = 0; i < row; i++)
for (let j = 0; j < col; j++)
if (visited[i][j] === false && grid[i][j] === 1)
let count = 0
count = bfs(grid, i, j, visited,count)
result = Math.max(result,count)
return result
;
dfs
var maxAreaOfIsland = function(grid)
// This function uses depth-first search algorithm to traverse the binary matrix grid.
const dfs = function(grid,i,j,visited)
const dirx = [-1,1,0,0]
const diry = [0,0,-1,1]
visited[i][j] = true
let area = 1
for(let k= 0;k<4;k++)
let curx = dirx[k] + i
let cury = diry[k] + j
if(curx < 0 || cury <0 || curx >= row || cury >=col) continue
if(visited[curx][cury] === false && grid[curx][cury] === 1)
visited[curx][cury] = true
area += dfs(grid,curx,cury,visited)
return area
const row = grid.length
const col = grid[0].length
let result = 0
let visited = new Array(row).fill(false).map(()=>new Array(col).fill(false))
for(let i = 0;i<row;i++)
for(let j = 0;j<col;j++)
if(visited[i][j] === false && grid[i][j] === 1)
result = Math.max(dfs(grid,i,j,visited),result)
return result
;
827. 最大人工岛(hard)
1020. 飞地的数量 (medium)
var numEnclaves = function(grid)
//bfs
const bfs = function(grid,i,j,visited,count)
let que = []
const dirx = [-1,1,0,0]
const diry = [0,0,-1,1]
que.push([i,j])
count ++
visited[i][j] = true
while(que.length > 0)
const [x,y] = que.shift()
for(let k = 0;k<4;k++)
let curx = x + dirx[k]
let cury = y + diry[k]
if(curx < 0 || cury < 0|| curx>=row || cury >= col) continue
if(visited[curx][cury] === false && grid[curx][cury] === 1)
que.push([curx,cury])
count ++
visited[curx][cury] = true
return count
const row = grid.length
const col = grid[0].length
let result = 0
let visited = new Array(row).fill(false).map(()=>new Array(col).fill(false))
for(let i = 0;i<row;i++)
if(visited[i][0] === false && grid[i][0] === 1)
bfs(grid,i,0,visited)
if(visited[i][col-1] === false && grid[i][col-1] === 1)
bfs(grid,i,col-1,visited)
for(let i = 0;i<col;i++)
if(visited[0][i] === false && grid[0][i] === 1)
bfs(grid,0,i,visited)
if(visited[row-1][i] === false && grid[row-1][i] === 1)
bfs(grid,row-1,i,visited)
for(let i = 0;i<row;i++)
for(let j = 0;j<col;j++)
if(visited[i][j] === false && grid[i][j] === 1)
let count = 0
count = bfs(grid,i,j,visited,count)
result += count
return result
;
这道题是先把边界的东西全部转化为true,但是并不需要给他计数。
130. 被围绕的区域
var solve = function(board)
const bfs = function(board,i,j)
const dirx = [-1,1,0,0]
const diry = [0,0,-1,1]
let que = []
que.push([i,j])
board[i][j] = "A"
while(que.length>0)
let [x,y] = que.shift()
for(let k = 0;k<4;k++)
let curx = dirx[k]+x
let cury = diry[k]+y
if(curx<0||cury<0||curx>=row||cury>=col) continue
if( board[curx][cury] === "O")
que.push([curx,cury])
board[curx][cury] = "A"
const row = board.length
const col = board[0].length
let visited = new Array(row).fill(false).map(()=>new Array(col).fill(false))
// 把边缘的都从O转化为了A
for(let i = 0;i<row;i++)
if(board[i][0] === "O") bfs(board,i,0)
if(board[i][col-1] === "O") bfs(board,i,col-1)
console.log(board)
for(let i = 0;i<col;i++)
if(board[0][i] === "O")
bfs(board,0,i)
if(board[row-1][i] === "O")
bfs(board,row-1,i)
console.log(board)
for(let i = 0;i<row;i++)
for(let j = 0;j<col;j++)
if(board[i][j] === "O")
board[i][j] = "X"
if(board[i][j] === "A")
board[i][j] = "O"
return board
;
这道题和飞地数量那道题一样的思路。需要注意的地方是,我们需要多次访问数组中的值,所以我们不能使用visited来标记,不然的话没有办法再遍历一次。
需要先把边缘的岛屿转化为A,然后第二部再遍历一次,如果遇到A就转化为O,如果遇到O就转化为A。
这些题都好容易写错,写=== 的时候很容易写成=
var solve = function (board)
const dfs = function (board, i, j)
const dirx = [-1, 1, 0, 0]
const diry = [0, 0, -1, 1]
board[i][j] = "A"
for (let k = 0; k < 4; k++)
let curx = dirx[k] + i
let cury = diry[k] + j
if (curx < 0 || cury < 0 || curx >= row || cury >= col) continue
if (board[curx][cury] === "O")
board[curx][cury] = "A"
dfs(board, curx, cury)
const row = board.length
const col = board[0].length
let visited = new Array(row).fill(false).map(() => new Array(col).fill(false))
// 把边缘的都从O转化为了A
for (let i = 0; i < row; i++)
if (board[i][0] === "O") dfs(board, i, 0)
if (board[i][col - 1] === "O") dfs(board, i, col - 1)
console.log(board)
for (let i = 0; i < col; i++)
if (board[0][i] === "O")
dfs(board, 0, i)
if (board[row - 1][i] === "O")
dfs(board, row - 1, i)
console.log(board)
for (let i = 0; i < row; i++)
for (let j = 0; j < col; j++)
if (board[i][j] === "O")
board[i][j] = "X"
if (board[i][j] === "A")
board[i][j] = "O"
return board
;
417. 太平洋大西洋水流问题(深搜、广搜)
var numIslands = function (grid)
// 使用dfs
let dirx = [-1, 1, 0, 0]
let diry = [0, 0, -1, 1]
let row = grid.length
let col = grid[0].length
const dfs = function (grid, visited, i, j)
//终止条件
//for循环
for (let k = 0; k < 4; k++)
let x = i + dirx[k]
let y = j + diry[k]
if (x >= row || y >= col || x < 0 || y < 0)
continue
if (visited[x][y] === false && grid[x][y] === '1')
visited[x][y] = true
dfs(grid, visited, x, y)
let visited = new Array(grid.length).fill(false).map(() => new Array(grid[0].length).fill(false))
let count = 0
for (let i = 0; i < row; i++)
for (let j = 0; j < col; j++)
if (visited[i][j] === false && grid[i][j] === '1')
visited[i][j] === true
count++;
dfs(grid, visited, i, j)
return count
;
127. 单词接龙 (困难)
841. 钥匙和房间
bfs
var canVisitAllRooms = function(rooms)
// 使用dfs深度优先算法,使用visited记录访问过的屋子,使用key拿到钥匙
const dfs = function(visited,room,key)
// 终止条件
if(visited[key])
return
// 单层递归逻辑
visited[key] = true
let keys = room[key]
for(let i = 0;i<keys.length;i++)
let newkey = keys[i]
dfs(visited,room,newkey)
// 返回值
let visited = new Array(rooms.length).fill(false)
dfs(visited,rooms,0)
for(let visit of visited)
console.log(visit)
if(visit === false)
return false
return true
;
dfs
var canVisitAllRooms = function(rooms)
// 使用dfs深度优先算法,使用visited记录访问过的屋子,使用key拿到钥匙
const bfs = function(visited,room,key)
// 终止条件
let que = []
que.push(room[key])
// 单层递归逻辑
visited[key] = true
while(que.length>0)
let keys = que.shift()
for(let i = 0;i<keys.length;i++)
let newkey = keys[i]
if(visited[newkey] === true) continue
visited[newkey] = true
que.push(room[newkey])
let visited = new Array(rooms.length).fill(false)
bfs(visited,rooms,0)
for(let visit of visited)
if(visit === false)
return false
return true
;
每日精华:https://www.yuque.com/chengxuyuancarl/wnx1np/ktwax2,训练营群里讨论的问题,都会做总结,放在每日精华里,方便大家回顾。
https://excalidraw.com/
大家平时刷题可以用这个网站画草稿图帮助理解!
https://www.cs.usfca.edu/~galles/visualization/Algorithms.html
数据结构和算法可视化可以看这个网站!
图论算法小结
图论算法内容难度较大,且灵活多变,本篇是对前述内容的小结
1. 图论算法设计难点
(1)如何将一个实际问题转化成图上的搜索问题(建模难)
(2)如何选择最优的搜索方式,搜索代价的代价函数怎么设计(构造难)
2. 算法一览
(1)图论基本算法(DFS、BFS、最小生成树(prim(贪心)、kruskal(贪心))、最短路径(dijkstra(贪心)、floyd(动态规划)))
(2)网络流算法(FF算法):算法过程、算法证明(最大流和最小割的对偶性)
(3)最大二分匹配算法:FF算法(最大匹配和最小覆盖的对偶性)、匈牙利算法
(4)可行解的搜索算法:爬山法(局部贪心)、Best-first(全局贪心)
(5)最优解的搜索算法:分支界限(例:多阶段图最短路径问题、人员安排问题)、A*算法(例:最短路径问题)
以上是关于算法61天|图论的主要内容,如果未能解决你的问题,请参考以下文章
图论最短路径问题(图的绘制以及Dijkstra算法和Bellman‐Ford算法)