切换主题
岛屿问题篇
在开始岛屿问题前先了解岛屿DFS模板(一篇非常优秀且易懂的岛屿总结):
JavaScript
const template = grid => {
const [row, col] = [grid.length, grid[0].length]
const dfs = (i, j) => {
// `base case`
if (i < 0 || i >= row || j < 0 || j >= col) return // 越界
if (grid[i][j] !== 'legalValue') return // 不符合要求
// 标记(已遍历过)
grid[i][j] = 'invalidValue'
dfs(i + 1, j)
dfs(i - 1, j)
dfs(i, j - 1)
dfs(i, j + 1)
}
/* 可能会有些预处理 */
// 遍历
for (let i = 0; i < row; i++) {
for (let j = 0; j < col; j++) {
if (grid[i][j] === 'legalValue') {
// do something
dfs(i, j)
}
}
}
}
岛屿数量
JavaScript
const numIslands = grid => {
const [row, col] = [grid.length, grid[0].length]
let ret = 0
const dfs = (i, j) => {
if (i < 0 || i >= row || j < 0 || j >= col) return
if (grid[i][j] !== '1') return
grid[i][j] = '2'
dfs(i + 1, j)
dfs(i - 1, j)
dfs(i, j - 1)
dfs(i, j + 1)
}
for (let i = 0; i < row; i++) {
for (let j = 0; j < col; j++) {
if (grid[i][j] === '1') {
ret++
dfs(i, j)
}
}
}
return ret
}
时间复杂度:O(row*col)
;空间复杂度:O(row*col)
。
封闭岛屿数量
JavaScript
const closedIsland = grid => {
const [row, col] = [grid.length, grid[0].length]
let ret = 0
const dfs = (i, j) => {
if (i < 0 || i >= row || j < 0 || j >= col) return
if (grid[i][j] !== 0) return
grid[i][j] = 2
dfs(i + 1, j)
dfs(i - 1, j)
dfs(i, j - 1)
dfs(i, j + 1)
}
// 逻辑上只需要额外先处理边界即可
for (let i = 0; i < row; i++) {
// 如果是第一行和最后一行,访问所有格子
// 如果不是,只访问第一列和最后一列的格子
const step = (i === 0 || i === row - 1) ? 1 : col - 1
for (let j = 0; j < col; j += step) {
dfs(i, j)
}
}
for (let i = 1; i < row; i++) {
for (let j = 1; j < col; j++) {
if (grid[i][j] === 0) {
ret++
dfs(i, j)
}
}
}
return ret
}
时间复杂度:O(row*col)
;空间复杂度:O(row*col)
。
统计子岛屿
JavaScript
const countSubIslands = (grid1, grid2) => {
const [row, col] = [grid1.length, grid1[0].length]
let ret = 0
const dfs = (i, j) => {
if (i < 0 || i >= row || j < 0 || j >= col) return
if (grid2[i][j] !== 1) return
grid2[i][j] = 2
dfs(i + 1, j)
dfs(i - 1, j)
dfs(i, j - 1)
dfs(i, j + 1)
}
// 如果在grid1里是水域,在grid2是陆地,把它及邻近的陆地淹掉,排除掉不符合子岛屿的陆地
for (let i = 0; i < row; i++) {
for (let j = 0; j < col; j++) {
if (grid1[i][j] == 0 && grid2[i][j] == 1) {
dfs(i, j);
}
}
}
for (let i = 0; i < row; i++) {
for (let j = 0; j < col; j++) {
if (grid2[i][j] === 1) {
ret++
dfs(i, j)
}
}
}
return ret
}
时间复杂度:O(row*col)
;空间复杂度:O(row*col)
。
飞地的数量
JavaScript
const closedIsland = grid => {
const [row, col] = [grid.length, grid[0].length]
let ret = 0
if(row < 3 || col < 3) return ret
const dfs = (i, j) => {
if (i < 0 || i >= row || j < 0 || j >= col) return
if (grid[i][j] !== 1) return
grid[i][j] = 2
dfs(i + 1, j)
dfs(i - 1, j)
dfs(i, j - 1)
dfs(i, j + 1)
}
// 逻辑上只需要额外先处理边界即可
for (let i = 0; i < row; i++) {
// 如果是第一行和最后一行,访问所有格子
// 如果不是,只访问第一列和最后一列的格子
const step = (i === 0 || i === row - 1) ? 1 : col - 1
for (let j = 0; j < col; j += step) {
dfs(i, j)
}
}
for (let i = 1; i < row; i++) {
for (let j = 1; j < col; j++) {
if (grid[i][j] === 1) {
ret++
}
}
}
return ret
}
时间复杂度:O(row*col)
;空间复杂度:O(row*col)
。
岛屿的周长
JavaScript
const islandPerimeter = grid => {
const [row, col] = [grid.length, grid[0].length]
const dfs = (i, j) => {
// 边界处提供 一条有效边
if (i < 0 || i >= row || j < 0 || j >= col) return 1
// 海洋陆地相交处提供 一条有效边
if (grid[i][j] === 0) return 1
if (grid[i][j] !== 1) return 0
grid[i][j] = 2
return dfs(i + 1, j)
+ dfs(i - 1, j)
+ dfs(i, j - 1)
+ dfs(i, j + 1)
}
for (let i = 0; i < row; i++) {
for (let j = 0; j < col; j++) {
if (grid[i][j] === 1) {
return dfs(i, j)
}
}
}
}
时间复杂度:O(row*col)
;空间复杂度:O(row*col)
。
岛屿的最大面积
JavaScript
const maxAreaOfIsland = grid => {
const [row, col] = [grid.length, grid[0].length]
let ret = 0
const dfs = (i, j) => {
if (i < 0 || i >= row || j < 0 || j >= col) return 0
if (grid[i][j] !== 1) return 0
grid[i][j] = 2
return dfs(i + 1, j)
+ dfs(i - 1, j)
+ dfs(i, j - 1)
+ dfs(i, j + 1)
+ 1
}
// 求封闭岛屿最大面积
// for(let i=0;i<row;i++) {
// const step= (i === 0 || i === row-1) ? 1 : col-1
// for(let j=0;j<col;j+=step) {
// dfs(i,j)
// }
// }
for (let i = 0; i < row; i++) {
for (let j = 0; j < col; j++) {
if (grid[i][j] === 1) {
ret = Math.max(dfs(i, j), ret)
}
}
}
return ret
}
时间复杂度:O(row*col)
;空间复杂度:O(row*col)
。