比较两个二进制矩阵网格以匹配孤岛(连接区域为“ 1”)

时间:2019-03-25 09:27:52

标签: javascript algorithm matrix array-algorithms

它与“ Number of Islands JavaScript”(挑战岛屿数量)https://codereview.stackexchange.com/questions/201530/count-number-of-islands-2d-grid非常相似。

给出两个网格,其中网格的每个单元格都包含“ 0”或“ 1”。如果两个单元共享一侧,则它们相邻。如果可以通过移动包含“ 1”的相邻单元格来到达该区域的任何单元格,则包含“ 1”的单元格将形成一个连接区域(或通常称为岛)。将第一个网格覆盖到第二个网格上,如果第一个网格的区域与第二个网格的区域完全匹配,则这些区域将匹配。计算第二个网格中此类匹配区域的总数

这是一个例子:

Grid 1
0 0 1
0 1 1
1 0 0

Grid 2
0 0 1
0 1 1
1 0 1

网格1在点{(0,2),(1,1),(1,2)}和{(2,0)}处形成两个区域

网格2在点{(0,2),(1,1),(1,2),(2,2)}和{(2,0)}处形成两个区域

区域{(2,0)}是唯一匹配的区域,因此答案是1。

这是我所做的。 我的函数countMatches()返回每个网格中连接区域的数量,但是我想要将网格1中的任何连接区域与网格2中的连接区域进行比较,并返回匹配的数量,即存在于网格中的精确连接区域的数量都。此结果将是一个整数

这也是指向它的代码笔链接-https://codepen.io/Baystef/pen/OqBJzG

JavaScript
function countMatches(grid1, grid2) {
    let gridOne = grid1.filter(n => typeof(n) !== 'number');
    let gridTwo = grid2.filter(n => typeof(n) !== 'number');

    //this only gives number of connected region in each grid, but what i want to get is number of islands that match perfectly when the grids are overlayed.
    return `We have ${countIslands(gridOne)} island(s) in grid 1 and ${countIslands(gridTwo)} island(s) in grid 2`
}

function countIslands(grid) {
    let markIsland = function (grid, x, y, visited) {
        if (x < 0 || x > grid.length - 1 || y < 0 || y > grid[x].length - 1) return;

        if (visited[x][y] === true) return;
        visited[x][y] = true;

        if (grid[x][y] === '0') return;

        markIsland(grid, x - 1, y, visited);
        markIsland(grid, x + 1, y, visited);
        markIsland(grid, x, y - 1, visited);
        markIsland(grid, x, y + 1, visited);
    };

    let visited = [];

    for (let i = 0; i < grid.length; i++) {
        visited[i] = [];
    }

    let count = 0;

    for (let x = 0; x < grid.length; x++) {
        for (let y = 0; y < grid[x].length; y++) {
            if (!visited[x][y] && grid[x][y] === '1') {
                count++;
                markIsland(grid, x, y, visited);
            }
            visited[x][y] = true;
        }
    }

    return count;
}

示例网格输入:-

const grid1_1 = [
    4,
    ['0', '1', '0', '0'],
    ['1', '0', '0', '1'],
    ['0', '0', '1', '1'],
    ['0', '0', '1', '1']
]
const grid2_1 = [
    4,
    ['0', '1', '0', '1'],
    ['1', '0', '0', '1'],
    ['0', '0', '1', '1'],
    ['0', '0', '1', '1']
]

const grid1_2 = [
    3,
    ['0', '0', '1'],
    ['0', '1', '1'],
    ['1', '0', '0']
]
const grid2_2 = [
    3,
    ['0', '0', '1'],
    ['0', '1', '1'],
    ['1', '0', '1']
]

每个网格的第一行包含一个整数,它是网格数组的大小,即4表示它是4 X 4网格。

如果我运行countMatches(grid1_1,grid2_1)函数,它将返回2。

原因是grid1_1具有3个相连的区域(岛屿),其位置为{(0,1)} , {(1,0)} and {(1,3),(2,2),(2,3),(3,2),(3,3)}

grid2_1在{(0,1)}, {(1,0)} and {(0,3),(1,3),(2,2),(2,3),(3,2),(3,3)}位置也有3个相连的区域(岛屿)

区域{(0,1)}, {(1,0)}是仅在grid1_1和grid2_1中唯一存在的两个区域,这就是函数应返回2的原因。

2 个答案:

答案 0 :(得分:0)

您可以先获取孤岛的数量,然后再将第二个数组与带有编号孤岛的数组进行比较。

此方法使用简化的数据集和具有孤岛计数长度的数组。

结果,matches数组的所有真实值都会被计数并重新调整。

  

示例:

   a          b       congruent islands/matching areas
-------    -------    --------------------------------
0 1 0 0    0 1 0 1
2 0 0 3    1 0 0 1
0 0 3 3    0 0 1 1
0 0 3 3    0 0 1 1    3/islands 1 2 3

0 1 0 2    0 1 0 0
3 0 0 2    1 0 0 1
0 0 2 2    0 0 1 1
0 0 2 2    0 0 1 1    2/islands 1 3

0 0 1      0 0 1
0 1 1      0 1 1
2 0 0      1 0 1      2/islands 1 2

0 0 1      0 0 1
0 1 1      0 1 1
2 0 1      1 0 0      1/islands 2

function getIslands(array) {

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

    var count = 1,
        islands = array.map(a => a.map(v => -v));
    islands.forEach((a, i, aa) => a.forEach((_, j) => test(aa, i, j, count) && count++));
    return { islands, count: count - 1 };
}

function countMatches(array1, array2) {
    var islands = getIslands(array1),
        matches = Array.from({ length: islands.count + 1 }).fill(true);

    islands.islands.forEach((a, i) => a.forEach((v, j) => matches[v] = matches[v] && array2[i][j] && v));
    islands.islands.forEach(a => console.log(...a));
    console.log('');
    array2.forEach(a => console.log(...a));
    console.log('islands', ...matches.filter(Boolean));
    return matches.reduce((s, b) => s + !!b, 0);
}

console.log(countMatches([[0, 1, 0, 0], [1, 0, 0, 1], [0, 0, 1, 1], [0, 0, 1, 1]], [[0, 1, 0, 1], [1, 0, 0, 1], [0, 0, 1, 1], [0, 0, 1, 1]]));
console.log(countMatches([[0, 1, 0, 1], [1, 0, 0, 1], [0, 0, 1, 1], [0, 0, 1, 1]], [[0, 1, 0, 0], [1, 0, 0, 1], [0, 0, 1, 1], [0, 0, 1, 1]]));
console.log(countMatches([[0, 0, 1], [0, 1, 1], [1, 0, 0]], [[0, 0, 1], [0, 1, 1], [1, 0, 1]]));
console.log(countMatches([[0, 0, 1], [0, 1, 1], [1, 0, 1]], [[0, 0, 1], [0, 1, 1], [1, 0, 0]]));
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 1 :(得分:-1)

//下面是使用dfs的工作代码

导入 java.util.Set;

公共类解决方案{

/*
 * Complete the 'countMatches' function below.
 *
 * The function is expected to return an INTEGER. The function accepts following
 * parameters: 1. STRING_ARRAY grid1 2. STRING_ARRAY grid2
 */
public static void main(String[] args) {
    List<String> grid1 = new ArrayList<>();
    grid1.add("001");
    grid1.add("011");
    grid1.add("100");
    List<String> grid2 = new ArrayList<>();
    grid2.add("001");
    grid2.add("011");
    grid2.add("101");
    System.out.println(countMatches(grid1, grid2));

}

static int[][] direction = new int[][] { { 0, -1 }, { -1, 0 }, { 1, 0 }, { 0, 1 } };

public static int countMatches(List<String> grid1, List<String> grid2) {
    // Write your code here
    Set<String> list1 = new HashSet<>();
    Set<String> list2 = new HashSet<>();
    boolean[][] visited1 = new boolean[grid1.size()][grid1.get(0).length()];
    boolean[][] visited2 = new boolean[grid1.size()][grid1.get(0).length()];
    for (int i = 0; i < grid1.size(); i++) {
        for (int j = 0; j < grid1.get(i).length(); j++) {
            if (grid1.get(i).charAt(j) == '1' && !visited1[i][j]) {
                visited1[i][j] = true;
                list1.add(dfs(grid1, i, j, visited1, new StringBuilder("(" + i + "," + j + ")")).toString());
            }
            if (grid2.get(i).charAt(j) == '1' && !visited2[i][j]) {
                visited2[i][j] = true;
                list2.add(dfs(grid2, i, j, visited2, new StringBuilder("(" + i + "," + j + ")")).toString());
            }
        }
    }
    int count = 0;
    System.out.println(list1);
    System.out.println(list2);
    for (String s : list1) {
        if (list2.contains(s))
            count++;
    }
    return count;
}

public static StringBuilder dfs(List<String> grid, int row, int col, boolean[][] visited, StringBuilder sb) {
    for (int i = 0; i < 4; i++) {
        int newRow = row + direction[i][0];
        int newCol = col + direction[i][1];
        if (isValid(grid, newRow, newCol) && !visited[newRow][newCol] && grid.get(newRow).charAt(newCol) == '1') {
            sb = sb.append("(" + newRow + "," + newCol + ")");
            visited[newRow][newCol] = true;
            dfs(grid, newRow, newCol, visited, sb);
        }
    }
    return sb;
}

public static boolean isValid(List<String> grid, int i, int j) {
    return i >= 0 && j >= 0 && i < grid.size() && j < grid.get(0).length();
}

}