数据结构—图中统计岛屿数量

585 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

其实许多算法并不是脱离实际的,很多图像处理问题都会用到图算法。下面分享一个关于图问题,就是计算地图中在海洋中岛屿的数量,我们将地图抽象为一个网格,将地图通过网格划分为一个一个小区域。每一个小区域表示一个陆地或者海洋。

island_count.png

  • 其中黄色表示 island
  • 蓝色表示海洋 问题是要找出地图中岛屿的数量。
const grid = [
    ['W','L','W','W','W'],
    ['W','L','W','W','W'],
    ['W','W','W','L','W'],
    ['W','W','L','L','W'],
    ['L','W','W','L','L'],
    ['L','L','W','W','W'],
]

用于一个二维矩阵来表示,每一个格子对应一个坐标(行,列)。

基本思路

思路很重要,有了思路也就是有一个找到答案方向,只要方向正确怎么走都能到终点,只是时间多少的问题了。

主要是遍历所有格子,每一个格子通过行数和列数可以确定其位置,我们通过位置来区分不同格子。从左上角开始下逐行移动一个指针,当指针遇到 island 时候,然后遍历其邻接的单元格,其邻接单元中为陆地的单元,检查是否已经经过该单元,如果经过则直接返回 false 跳过,如果是没有经过的单元,则进行遍历,也就是深度优先遍历,将所有与该陆地可以连通的陆地单元遍历到并进行标记为访问过。

island_count_002.png

遍历所有单元格

for(let r = 0; r < grid.length; r +=1){
    for(let c = 0; c < grid[0].length; c +=1){
       if(explore(grid,r,c,visited) === true){
            count +=1
       }
    }
}

遍历所有单元格

设置遍历的边界

const rowInbounds = 0 <= r && r < grid.length;
const columnInbounds = 0 <= c && c < grid[0].length;
if (!rowInbounds || !columnInbounds) return false

为游走指针设置边界,然指针在地图范围内游走。也可以在下面遍历其邻接单元处进行控制指针移动范围,不过在开始控制显得更加优雅。

标记经过的单元格

const pos = r +',' + c;
if(visited.has(pos)) return false;
visited.add(pos);

为了标记经过单元格可以利用 Set 来保存经过的单元格,单元格可以[r,c],这样 Set就无法保持一致性。

完整代码

/**
 * r = # rows
 * c = # cols
 * Time:O(r c)
 * Space: O(rc)
 */

const grid = [
    ['W','L','W','W','W'],
    ['W','L','W','W','W'],
    ['W','W','W','L','W'],
    ['W','W','L','L','W'],
    ['L','W','W','L','L'],
    ['L','L','W','W','W'],
]

const islandCount = (grid) =>{
    let count = 0
    const visited = new Set();
    for(let r = 0; r < grid.length; r +=1){
        for(let c = 0; c < grid[0].length; c +=1){
           if(explore(grid,r,c,visited) === true){
                count +=1
           }
        }
    }
    return count
}

const explore = (grid,r,c,visited) => {
    const rowInbounds = 0 <= r && r < grid.length;
    const columnInbounds = 0 <= c && c < grid[0].length;
    if (!rowInbounds || !columnInbounds) return false

    if(grid[r][c] === 'W') return false;


    const pos = r +',' + c;
    if(visited.has(pos)) return false;
    visited.add(pos);

    explore(grid,r -1, c,visited);
    explore(grid,r +1, c,visited);
    explore(grid,r, c-1,visited);
    explore(grid,r, c+1,visited);


    return true;
}



const res = islandCount(grid);
console.log(res)