【问题标题】:island count two-dimensional array algorithm孤岛计数二维数组算法
【发布时间】:2021-08-14 11:29:03
【问题描述】:
let arr = [[1, 0, 1],
           [1, 0, 0],
           [1, 1, 1]
     ];

我有数组,其中 1 岛和 0 水。我需要写一个岛屿计数器。这里有 2 岛 1 大和 1 小(单人)。例如这里有 5 个单岛

let arr = [[1, 0, 1],
           [0, 1, 0],
           [1, 0, 1]
     ]; 

我写了双循环来吸引数组中的每个项目,如下所示:

for(let i = 0; i < arr.length; i++){
    for(let x = 0; x < arr[i].length; x++){
         if(...){}
    }
 }

我需要为此编写 сondition。请帮帮我。

【问题讨论】:

  • 想要的结果是什么?岛屿的数量?尺寸?
  • 对不起,我忘了写。我需要岛屿数
  • 到目前为止你尝试过什么?你被困在哪里了?您在寻找哪种“条件”?

标签: javascript algorithm


【解决方案1】:

您可以使用计数器并检查所有相邻项目并使用实际计数器更新元素。

function check(array) {

    function test(array, i, j, value) {
        if (array[i] && array[i][j] === -1) {
            array[i][j] = value;
            test(array, i -1, j, value);
            test(array, i + 1, j, value);
            test(array, i, j - 1, value);
            test(array, i, j + 1, value);
            return true;
        }
    }
    var value = 1;

    array.forEach(a=> a.forEach((b, i, bb) => bb[i] = -b));
    array.forEach((a, i, aa) => a.forEach((b, j) => test(aa, i, j, value) && value++));
    document.getElementById('out').innerHTML += array.map(a => a.join(' ')).join('\n') + '<hr>';
    return value - 1;
}

console.log(check([[1, 0, 1], [1, 0, 0], [1, 1, 1]]));
console.log(check([[1, 0, 1], [0, 1, 0], [1, 0, 1]]));
&lt;pre id="out"&gt;&lt;/pre&gt;

【讨论】:

    【解决方案2】:

    我喜欢这个问题。这是一个基本的。因此,就我能想到的而言,应该有一个有效的算法。我认为它需要递归。

    /**
     * function to resolve islands
     * @param  {Array} map     - the world map we provide
     * @param  {Array} islands - 2D array considiting of island arrays each
     *                           holding island coordinates. Defaults to []
     * @return {Array} islands - "
    **/
    function resolveIslands(map, islands = []){
    
      /**
       * function to take a coordinate and split 4 neighboring coordinates into 1s and 0s
       * @param  {Number} r - 0 indexed row value
       * @param  {Number} c - 0 indexed column value
       * @return {Array}    - coordinates of 0s and 1s split in the form of [[0s],[1s]]
      * */
      function splitRoutes(r,c){
        return [[r-1,c],[r,c-1],[r+1,c],[r,c+1]].reduce((p,[r,c]) => map[r]    === void 0 ||
                                                                     map[r][c] === void 0 ? p
                                                                                          : map[r][c] ? (p[1].push([r,c]),p)
                                                                                                      : (p[0].push([r,c]),p), [[],[]]);
      }
      
      /**
       * function to take a coordinate and solve the island if the coordinate is 1
       * @param {Number} r     - 0 index row value
       * @param {Number} c     - 0 index column value
       * @param {Array} island - An array of arrays of coordinates representing the
                                 currently resolved island
       * @param {Number} oc    - The number of 1s in da hood
       * @param {Array} tz     - Gradually becoming all available zeros in the map
                                 initially []
       * @return {Undefined}   - Full of side effects :)
      * */
      function scan(r, c, island = [], oc = 0, tz = []){
        var [toZeros,toOnes] = splitRoutes(r,c);
        tz.push(...toZeros);
        switch (map[r][c]) {
          case 1: !island.length && islands.push(island);
                  oc += toOnes.length;
                  map[r][c] = void 0;
                  island.push([r,c]);
                  toOnes.forEach(([r,c]) => scan(r,c,island,--oc,tz));
                  !oc && tz.forEach(([r,c]) => map[r][c] === 0 && scan(r,c,island,oc,tz));
                  break;
          case 0: map[r][c] = void 0;
                  toOnes.forEach(([r,c]) => map[r][c] === 1 && scan(r,c));
                  tz.forEach(([r,c]) => map[r][c] === 0 && scan(r,c));
                  break;
        }
      }
      scan(0,0);
      return islands;
    }
    
    
    
    let arr = [[1, 0, 1],
               [1, 0, 0],
               [1, 1, 1]
              ],
        brr = [[1, 0, 1, 1, 1],
               [0, 1, 0, 0, 1],
               [1, 0, 1 ,1, 0],
               [0, 0, 0, 0, 1],
               [1, 1, 0, 1, 1]
              ];
    
    console.log(JSON.stringify(resolveIslands(arr)));
    console.log(JSON.stringify(resolveIslands(brr)));

    primaryRoutes(r,c) 实用函数接受一个坐标,并在一个数组中返回我们接下来可以访问的路线。包含 1 的路线优先,包含 0 的路线延迟(放在队列的后面),地图外或之前访问过的 0 的路线将被忽略。

    每个访问的单元格都变成void 0,这是一个完美的undefined

    这比公认的答案稍慢,但考虑到您也获得了岛屿坐标,我仍然认为它是有效的。因此,为了获得找到的岛屿的数量,您需要检查结果数组的 length 属性。

    【讨论】:

      【解决方案3】:

      一个更详细的答案,更容易理解:

      function gridToList(grid, rows, column){
        var lg = [];
        var gridString = "<p>";
        for(var z = 0; z < grid.length; z++){
          gridString = gridString.concat("[");
          gridString = gridString.concat(grid[z]);
          lg = lg.concat(grid[z]);
          gridString = gridString.concat("]<br/>");
          gridString = gridString.concat("</p>");
        }
        var el = document.getElementById("initialData");
        if(el){
            el.innerHTML = "rows:" + rows + "<br>" +
          "column:" + column + "<br>" +
          "grid:" + gridString + "<br>";
        }
        return lg
      }
      
      function numberAmazonGoStores(rows, column, grid)
      {
        var idm = {};
      
        lg = gridToList(grid, rows, column);
      
        for(var z = 0; z < lg.length; z++){
          if(lg[z]){
            idm[z] = 1;
          }
        }
      
        var findNeighbors = function(b) {
      
          var currentBuilding = parseInt(b);
          var currRow = Math.floor(currentBuilding/column);
      
          //remove value from map so we dont re-traverse it.
          delete idm[currentBuilding];
      
          var u,d,l,r;
      
          // u = - column if > 0
          u = currentBuilding - column;
          if(idm[u]) {
            findNeighbors(u);
          }
      
          // d = + column if < column*rows
          d = currentBuilding + column;
          if(idm[d]) {
            findNeighbors(d);
          }
      
          // l = - 1 if > 0 && same row;
          l = currentBuilding - 1;
          var lRow = Math.floor(l/column);
          if(lRow === currRow && idm[l]) {
            findNeighbors(l);
          }
      
          // r = + 1 if < row && same row;
          r = currentBuilding + 1;
      
          var rRow = Math.floor(r/column);
          if(rRow === currRow && idm[r]) {
            findNeighbors(r);
          }
        }
      
        var clusters = 0;
        // loop over non traversed values in map
        for(p in idm){
          if(idm[p]){
            findNeighbors(p);
          }
          clusters += 1;
        }
        console.log("grid size = " + lg.length);
        console.log("total clusters found: " + clusters)
        return clusters;
      }
      
      g = [
      [1,1,1,1],
      [1,1,1,1],
      [0,0,0,0],
      [0,1,0,1]
      ]
      numberAmazonGoStores(4,4,g);
      
      g2 = [
      [1,1,0,0,0],
      [0,0,0,1,1],
      [0,1,0,0,0],
      [1,0,1,1,0],
      [0,1,0,0,1],
      [1,0,1,0,1],
      [0,1,0,1,0]
      ];
      numberAmazonGoStores(7,5,g2);
      

      【讨论】:

      • 解决问题的具体算法是什么?
      • 只有在浏览器中才会更冗长
      • @NinaScholz 我称之为递归部门优先搜索。这是来自互联网的一个小sn-p:遍历图表。 ...您可以通过遍历图形的所有顶点轻松地做到这一点,对检查时仍未访问的每个顶点执行算法。图的遍历通常使用两种算法:深度优先搜索 (DFS) 和广度优先搜索 (BFS)。
      • @LucaKiebel 我说它更冗长主要是因为我没有嵌套循环或链式操作。取而代之的是,我确保每个逻辑部分都分列在不同的行中,以便读者可以更轻松地通过逻辑。对于那些想要快速复制、粘贴和运行的人来说,日志记录和 ui 更新只是节食。
      【解决方案4】:
      const map = [
        [1, 0, 0, 0, 1],
        [0, 0, 1, 0, 0],
        [0, 1, 0, 0, 1],
        [0, 1, 1, 1, 1],
        [0, 0, 0, 1, 1]
      ];
      
      function findIslands(arr) {
        let rows = arr.length,
          cols = arr[0].length; // matrix dimentions
      
        let islands = 0;
        let eaten = []; // connected islands on the latest iterations
      
        let left = 0, // island on the left
          up = 0; // island on the right
      
        for (let row = 0; row < rows; row++) {
          for (let col = 0; col < cols; col++) {
            if (!arr[row][col]) {
              continue; // skip zero (water)
            }
            left = col > 0 ?
              arr[row][col - 1] :
              0;
      
            up = row > 0 ?
              arr[row - 1][col] :
              0;
            if (!left && !up) { // new island starts if there is water on the left and up
              islands++;
              arr[row][col] = islands; // give a number to island 
            } else if (left && up && left !== up) { //upper island is not seperate
              arr[row][col] = left;
              eaten.push(up)
            } else if (left) {
              arr[row][col] = left; // island continues previous island to the right
            } else if (up) {
              arr[row][col] = up; // island continues previous island
            }
          }
        }
        console.table(arr)
        return islands - eaten.length;
      }
      
      console.log('найдено островов ', findIslands(map))
      

      【讨论】:

      • 请在您的答案中添加一些解释,以便其他人可以从中学习
      猜你喜欢
      • 1970-01-01
      • 2020-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-16
      • 2018-05-20
      • 2016-12-13
      相关资源
      最近更新 更多