Day51-图论,leetcode200, 105

  1. 卡码网-岛屿数量
  • 题目描述:给定一个由 1(陆地)和 0(水)组成的矩阵,你需要计算岛屿的数量。岛屿由水平方向或垂直方向上相邻的陆地连接而成,并且四周都是水域。你可以假设矩阵外均被水包围。

  • 输入描述:第一行包含两个整数 N, M,表示矩阵的行数和列数。后续 N 行,每行包含 M 个数字,数字为 1 或者 0。

  • 输出描述:输出一个整数,表示岛屿的数量。如果不存在岛屿,则输出 0。


  • 输入示例
  • 4 5
  • 1 1 0 0 0
  • 1 1 0 0 0
  • 0 0 1 0 0
  • 0 0 0 1 1
  • 输出示例
  • 3

  • 思路
// 深搜dfs版本
const r1 = require('readline').createInterface({ input: process.stdin });
// 创建readline接口
let iter = r1[Symbol.asyncIterator]();
// 创建异步迭代器
const readline = async () => (await iter.next()).value;

let graph
let N, M
let visited
let result = 0
const dir = [[0, 1], [1, 0], [0, -1], [-1, 0]]

// 读取输入,初始化地图
const initGraph = async () => {
  let line = await readline();
  [N, M] = line.split(' ').map(Number);
  graph = new Array(N).fill(0).map(() => new Array(M).fill(0))
  visited = new Array(N).fill(false).map(() => new Array(M).fill(false))

  for (let i = 0; i < N; i++) {
    line = await readline()
    line = line.split(' ').map(Number)
    for (let j = 0; j < M; j++) {
      graph[i][j] = line[j]
    }
  }
}

/**
 * @description: 从节点x,y开始深度优先遍历
 * @param {*} graph 是地图,也就是一个二维数组
 * @param {*} visited 标记访问过的节点,不要重复访问
 * @param {*} x 表示开始搜索节点的下标
 * @param {*} y 表示开始搜索节点的下标
 * @return {*}
 */
const dfs = (graph, visited, x, y) => {
  for (let i = 0; i < 4; i++) {
    const nextx = x + dir[i][0]
    const nexty = y + dir[i][1]
    if (nextx < 0 || nextx >= N || nexty < 0 || nexty >= M) continue
    if (!visited[nextx][nexty] && graph[nextx][nexty] === 1) {
      visited[nextx][nexty] = true
      dfs(graph, visited, nextx, nexty)
    }
  }
}

(async function () {
  // 读取输入,初始化地图
  await initGraph()

  // 统计岛屿数
  for (let i = 0; i < N; i++) {
    for (let j = 0; j < M; j++) {
      if (!visited[i][j] && graph[i][j] === 1) {
        // 标记已访问
        visited[i][j] = true

        // 遇到没访问过的陆地,+1
        result++

        // 深度优先遍历,将相邻陆地标记为已访问
        dfs(graph, visited, i, j)
      }
    }
  }
  console.log(result);
})()

// 广搜bfs
const r1 = require('readline').createInterface({ input: process.stdin });
// 创建readline接口
let iter = r1[Symbol.asyncIterator]();
// 创建异步迭代器
const readline = async () => (await iter.next()).value;

let graph
let N, M
let visited
let result = 0
const dir = [[0, 1], [1, 0], [0, -1], [-1, 0]]

// 读取输入,初始化地图
const initGraph = async () => {
  let line = await readline();
  [N, M] = line.split(' ').map(Number);
  graph = new Array(N).fill(0).map(() => new Array(M).fill(0))
  visited = new Array(N).fill(false).map(() => new Array(M).fill(false))

  for (let i = 0; i < N; i++) {
    line = await readline()
    line = line.split(' ').map(Number)
    for (let j = 0; j < M; j++) {
      graph[i][j] = line[j]
    }
  }
}


/**
 * @description: 从(x, y)开始广度优先遍历
 * @param {*} graph 地图
 * @param {*} visited 访问过的节点
 * @param {*} x 开始搜索节点的下标
 * @param {*} y 开始搜索节点的下标
 * @return {*}
 */
const bfs = (graph, visited, x, y) => {
  let queue = []
  queue.push([x, y])
  visited[x][y] = true  //只要加入队列就立刻标记为访问过

  while (queue.length) {
    let [x, y] = queue.shift()
    for (let i = 0; i < 4; i++) {
      let nextx = x + dir[i][0]
      let nexty = y + dir[i][1]
      if(nextx < 0 || nextx >= N || nexty < 0 || nexty >= M) continue
      if(!visited[nextx][nexty] && graph[nextx][nexty] === 1){
        queue.push([nextx, nexty])
        visited[nextx][nexty] = true
      }
    }
  }

}

(async function () {

  // 读取输入,初始化地图
  await initGraph()

  // 统计岛屿数
  for (let i = 0; i < N; i++) {
    for (let j = 0; j < M; j++) {
      if (!visited[i][j] && graph[i][j] === 1) {
        // 遇到没访问过的陆地,+1
        result++

        // 广度优先遍历,将相邻陆地标记为已访问
        bfs(graph, visited, i, j)
      }
    }
  }
  console.log(result);
})()


  1. 岛屿数量
  • 给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。
  • 岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
  • 此外,你可以假设该网格的四条边均被水包围。

  • 思路
  • 遇到一个没有遍历过的节点陆地,计数器就加一,然后把该节点陆地所能遍历到的陆地都标记上。再遇到标记过的陆地节点和海洋节点的时候直接跳过。 这样计数器就是最终岛屿的数量。
// 深搜dfs
var numIslands = function(grid) {
    if (!grid || grid.length == 0 || grid[0].length == 0) return 0
    let nRow = grid.length
    let mColumn = grid[0].length
    let result = 0
    const dir = [[0, 1], [1, 0], [0, -1], [-1, 0]] // 四个方向:右、下、左、上
    let visited = new Array(nRow).fill().map(() => new Array(mColumn).fill(false))

    const dfs = (grid, visited, x, y) => {
        // 终止条件:访问过的节点或者遇到海水
        if (grid[x][y] == 0 || visited[x][y] == 1) {
            return
        }
        visited[x][y] = true // 标记访问过
        for (let i = 0; i < 4; i++) {
            const nextx = x + dir[i][0]
            const nexty = y + dir[i][1]
            if (nextx < 0 || nextx >= nRow || nexty < 0 || nexty >= mColumn) continue // 越界了,直接跳过
            dfs(grid, visited, nextx, nexty)
        }
    }

    for (let i = 0; i < nRow; i++) {
        for(let j = 0; j < mColumn; j++) {
            if (grid[i][j] == 1 && !visited[i][j]) {
                result++ // 遇到没访问过的陆地,+1
                dfs(grid, visited, i, j). // 将与其链接的陆地都标记上 true
            }
        }
    }
    return result
};

// 广搜BFS
var numIslands = function(grid) {
    if (!grid || grid.length == 0 || grid[0].length == 0) return 0
    let nRow = grid.length
    let mColumn = grid[0].length
    let result = 0
    const dir = [[0, 1], [1, 0], [0, -1], [-1, 0]] // 四个方向:右、下、左、上
    let visited = new Array(nRow).fill().map(() => new Array(mColumn).fill(false))

    const bfs = (grid, visited, x, y) => {
        let queue = []
        queue.push([x, y])
        visited[x][y] = true // 标记访问过
        while(queue.length) {
           let [x, y] = queue.shift()
           for (let i = 0; i < 4; i++) {
                const nextx = x + dir[i][0]
                const nexty = y + dir[i][1]
                if (nextx < 0 || nextx >= nRow || nexty < 0 || nexty >= mColumn) continue // 越界了,直接跳过
                if (!visited[nextx][nexty] && grid[nextx][nexty] == 1) {
                    queue.push([nextx, nexty])
                    visited[nextx][nexty] = true
                }
               
            } 
        }
        
    }

    for (let i = 0; i < nRow; i++) {
        for(let j = 0; j < mColumn; j++) {
            if (grid[i][j] == 1 && !visited[i][j]) {
                result++ // 遇到没访问过的陆地,+1
                bfs(grid, visited, i, j)  // 将与其链接的陆地都标记上 true
            }
        }
    }
    return result
};


  1. 卡码网-岛屿的最大面积
  • 题目描述:给定一个由 1(陆地)和 0(水)组成的矩阵,计算岛屿的最大面积。岛屿面积的计算方式为组成岛屿的陆地的总数。岛屿由水平方向或垂直方向上相邻的陆地连接而成,并且四周都是水域。你可以假设矩阵外均被水包围。
  • 输入描述:第一行包含两个整数 N, M,表示矩阵的行数和列数。后续 N 行,每行包含 M 个数字,数字为 1 或者 0,表示岛屿的单元格。
  • 输出描述:输出一个整数,表示岛屿的最大面积。如果不存在岛屿,则输出 0。

  • 输入示例
  • 4 5
  • 1 1 0 0 0
  • 1 1 0 0 0
  • 0 0 1 0 0
  • 0 0 0 1 1
  • 输出示例
  • 4

  • 思路
  • 写法一:dfs处理当前节点的相邻节点,即在主函数遇到岛屿就计数为1,dfs处理接下来的相邻陆地
// 深搜版 一
const r1 = require('readline').createInterface({ input: process.stdin });
// 创建readline接口
let iter = r1[Symbol.asyncIterator]();
// 创建异步迭代器
const readline = async () => (await iter.next()).value;

let graph // 地图
let N, M // 地图大小
let visited // 访问过的节点
let result = 0 // 最大岛屿面积
let count = 0 // 岛屿内节点数
const dir = [[0, 1], [1, 0], [0, -1], [-1, 0]] //方向

// 读取输入,初始化地图
const initGraph = async () => {
  let line = await readline();
  [N, M] = line.split(' ').map(Number);
  graph = new Array(N).fill(0).map(() => new Array(M).fill(0))
  visited = new Array(N).fill(false).map(() => new Array(M).fill(false))

  for (let i = 0; i < N; i++) {
    line = await readline()
    line = line.split(' ').map(Number)
    for (let j = 0; j < M; j++) {
      graph[i][j] = line[j]
    }
  }
}

/**
 * @description: 从(x, y)开始深度优先遍历
 * @param {*} graph 地图
 * @param {*} visited 访问过的节点
 * @param {*} x 开始搜索节点的下标
 * @param {*} y 开始搜索节点的下标
 * @return {*}
 */
const dfs = (graph, visited, x, y) => {
  for (let i = 0; i < 4; i++) {
    let nextx = x + dir[i][0]
    let nexty = y + dir[i][1]
    if(nextx < 0 || nextx >= N || nexty < 0 || nexty >= M) continue
    if(!visited[nextx][nexty] && graph[nextx][nexty] === 1){
      count++
      visited[nextx][nexty] = true
      dfs(graph, visited, nextx, nexty)
    }
  }
}

(async function () {

  // 读取输入,初始化地图
  await initGraph()

  // 统计最大岛屿面积
  for (let i = 0; i < N; i++) {
    for (let j = 0; j < M; j++) {
      if (!visited[i][j] && graph[i][j] === 1) { //遇到没有访问过的陆地
        // 重新计算面积
        count = 1
        visited[i][j] = true

        // 深度优先遍历,统计岛屿内节点数,并将岛屿标记为已访问
        dfs(graph, visited, i, j)

        // 更新最大岛屿面积
        result = Math.max(result, count)
      }
    }
  }
  console.log(result);
})()

  • 写法二:dfs处理当前节点,即在主函数遇到岛屿就计数为0,dfs处理接下来的全部陆地
// 深搜版 二
const r1 = require('readline').createInterface({ input: process.stdin });
// 创建readline接口
let iter = r1[Symbol.asyncIterator]();
// 创建异步迭代器
const readline = async () => (await iter.next()).value;

let graph // 地图
let N, M // 地图大小
let visited // 访问过的节点
let result = 0 // 最大岛屿面积
let count = 0 // 岛屿内节点数
const dir = [[0, 1], [1, 0], [0, -1], [-1, 0]] // 四个方向

// 读取输入,初始化地图
const initGraph = async () => {
  let line = await readline();
  [N, M] = line.split(' ').map(Number);
  graph = new Array(N).fill(0).map(() => new Array(M).fill(0))
  visited = new Array(N).fill(false).map(() => new Array(M).fill(false))

  for (let i = 0; i < N; i++) {
    line = await readline()
    line = line.split(' ').map(Number)
    for (let j = 0; j < M; j++) {
      graph[i][j] = line[j]
    }
  }
}

/**
 * @description: 从(x, y)开始深度优先遍历
 * @param {*} graph 地图
 * @param {*} visited 访问过的节点
 * @param {*} x 开始搜索节点的下标
 * @param {*} y 开始搜索节点的下标
 * @return {*}
 */
const dfs = (graph, visited, x, y) => {
    if (visited[x][y] || graph[x][y] == 0) return; // 终止条件:访问过的节点 或者 遇到海水
    visited[x][y] = true; // 标记访问过
    count++;
    for (let i = 0; i < 4; i++) {
        let nextx = x + dir[i][0]
        let nexty = y + dir[i][1]
        if(nextx < 0 || nextx >= N || nexty < 0 || nexty >= M) continue
        dfs(graph, visited, nextx, nexty)
    }
}

(async function () {

  // 读取输入,初始化地图
  await initGraph()

  // 统计最大岛屿面积
  for (let i = 0; i < N; i++) {
    for (let j = 0; j < M; j++) {
      if (!visited[i][j] && graph[i][j] === 1) { //遇到没有访问过的陆地
        // 重新计算面积
        count = 0 // 因为dfs处理当前节点,所以遇到陆地计数为0,进dfs之后在开始从1计数

        // 深度优先遍历,统计岛屿内节点数,并将岛屿标记为已访问
        dfs(graph, visited, i, j) // 将与其链接的陆地都标记上 true

        // 更新最大岛屿面积
        result = Math.max(result, count)
      }
    }
  }
  console.log(result);
})()

  • 广搜bfs
// 广搜版

const r1 = require('readline').createInterface({ input: process.stdin });
// 创建readline接口
let iter = r1[Symbol.asyncIterator]();
// 创建异步迭代器
const readline = async () => (await iter.next()).value;

let graph // 地图
let N, M // 地图大小
let visited // 访问过的节点
let result = 0 // 最大岛屿面积
let count = 0 // 岛屿内节点数
const dir = [[0, 1], [1, 0], [0, -1], [-1, 0]] //方向


// 读取输入,初始化地图
const initGraph = async () => {
  let line = await readline();
  [N, M] = line.split(' ').map(Number);
  graph = new Array(N).fill(0).map(() => new Array(M).fill(0))
  visited = new Array(N).fill(false).map(() => new Array(M).fill(false))

  for (let i = 0; i < N; i++) {
    line = await readline()
    line = line.split(' ').map(Number)
    for (let j = 0; j < M; j++) {
      graph[i][j] = line[j]
    }
  }
}


/**
 * @description: 从(x, y)开始广度优先遍历
 * @param {*} graph 地图
 * @param {*} visited 访问过的节点
 * @param {*} x 开始搜索节点的下标
 * @param {*} y 开始搜索节点的下标
 * @return {*}
 */
const bfs = (graph, visited, x, y) => {
  let queue = []
  queue.push([x, y])
  count++
  visited[x][y] = true  //只要加入队列就立刻标记为访问过

  while (queue.length) {
    let [xx, yy] = queue.shift()
    for (let i = 0; i < 4; i++) {
      let nextx = xx + dir[i][0]
      let nexty = yy + dir[i][1]
      if(nextx < 0 || nextx >= N || nexty < 0 || nexty >= M) continue
      if(!visited[nextx][nexty] && graph[nextx][nexty] === 1){
        queue.push([nextx, nexty])
        count++
        visited[nextx][nexty] = true
      }
    }
  }

}

(async function () {

  // 读取输入,初始化地图
  await initGraph()

  // 统计最大岛屿面积
  for (let i = 0; i < N; i++) {
    for (let j = 0; j < M; j++) {
      if (!visited[i][j] && graph[i][j] === 1) { //遇到没有访问过的陆地
        // 重新计算面积
        count = 0

        // 广度优先遍历,统计岛屿内节点数,并将岛屿标记为已访问
        bfs(graph, visited, i, j)

        // 更新最大岛屿面积
        result = Math.max(result, count)
      }
    }
  }
  console.log(result);
})()


  1. LCR 岛屿的最大面积
  • 给定一个由 0 和 1 组成的非空二维数组 grid ,用来表示海洋岛屿地图。
  • 一个 岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在水平或者竖直方向上相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。
  • 找到给定的二维数组中最大的岛屿面积。如果没有岛屿,则返回面积为 0 。

  • 思路
  • 写法一:dfs处理当前节点的相邻节点,即在主函数遇到岛屿就计数为1,dfs处理接下来的相邻陆地
/**
 * @param {number[][]} grid
 * @return {number}
 */
var maxAreaOfIsland = function(grid) {
    if (!grid || grid.length == 0 || grid[0].length == 0) {
        return 0
    }
    let n = grid.length
    let m = grid[0].length
    let visited = new Array(n).fill().map(() => new Array(m).fill(false))
    const dir = [[0, 1], [1, 0], [0, -1], [-1, 0]]
    let result = 0
    let count = 0

    const dfs = (grid, visited, x, y) => {
        for (let i = 0; i < 4; i++) {
            let nextx = x + dir[i][0]
            let nexty = y + dir[i][1]
            if (nextx < 0 || nextx >= n || nexty < 0 || nexty >= m) continue
            if (grid[nextx][nexty] == 1 && !visited[nextx][nexty]) {
                count++
                visited[nextx][nexty] = true
                dfs(grid, visited, nextx, nexty)
            }
        }
    }
    for (let i = 0; i < n; i++) {
        for (j = 0; j < m; j++) {
            console.log('111')
            if (grid[i][j] == 1 && !visited[i][j]) {
                count = 1
                visited[i][j] = true
                dfs(grid, visited, i, j)
                result = Math.max(result, count)
            }
        }
    }
    return result
};

  • 写法二:dfs处理当前节点,即在主函数遇到岛屿就计数为0,dfs处理接下来的全部陆地
/**
 * @param {number[][]} grid
 * @return {number}
 */
var maxAreaOfIsland = function(grid) {
    if (!grid || grid.length == 0 || grid[0].length == 0) {
        return 0
    }
    let n = grid.length
    let m = grid[0].length
    let visited = new Array(n).fill().map(() => new Array(m).fill(false))
    const dir = [[0, 1], [1, 0], [0, -1], [-1, 0]]
    let result = 0
    let count = 0

    const dfs = (grid, visited, x, y) => {
        if (visited[x][y] || grid[x][y] == 0) return 
        visited[x][y] = true
        count++
        for (let i = 0; i < 4; i++) {
            let nextx = x + dir[i][0]
            let nexty = y + dir[i][1]
            if (nextx < 0 || nextx >= n || nexty < 0 || nexty >= m) continue
            dfs(grid, visited, nextx, nexty)
        }
    }
    for (let i = 0; i < n; i++) {
        for (j = 0; j < m; j++) {
            if (grid[i][j] == 1 && !visited[i][j]) {
                count = 0
                dfs(grid, visited, i, j)
                result = Math.max(result, count)
            }
        }
    }
    return result
};

  • 广搜版bfs
var maxAreaOfIsland = function(grid) {
    if (!grid || grid.length == 0 || grid[0].length == 0) {
        return 0
    }
    let n = grid.length
    let m = grid[0].length
    let visited = new Array(n).fill().map(() => new Array(m).fill(false))
    const dir = [[0, 1], [1, 0], [0, -1], [-1, 0]]
    let result = 0
    let count = 0

    const bfs = (grid, visited, x, y) => {
        let queue = []
        queue.push([x, y])
        count++
        visited[x][y] = true
        while (queue.length) {
            let [x, y] = queue.shift()
           for (let i = 0; i < 4; i++) {
                let nextx = x + dir[i][0]
                let nexty = y + dir[i][1]
                if (nextx < 0 || nextx >= n || nexty < 0 || nexty >= m) continue
                if (!visited[nextx][nexty] && grid[nextx][nexty] == 1) {
                    queue.push([nextx, nexty])
                    count++
                    visited[nextx][nexty] = true
                }
            } 
        }
        
    }
    for (let i = 0; i < n; i++) {
        for (j = 0; j < m; j++) {
            if (grid[i][j] == 1 && !visited[i][j]) {
                count = 0
                bfs(grid, visited, i, j)
                result = Math.max(result, count)
            }
        }
    }
    return result
};



参考&感谢各路大神

posted @ 2025-07-17 14:41  安静的嘶吼  阅读(5)  评论(0)    收藏  举报