如何确定矩阵中相同邻居的数量?

时间:2014-02-01 21:02:19

标签: java matrix

我有一个对象数组,其枚举为1或0。 它可能看起来像这样:

0 0 1 0
0 1 1 0
0 0 0 1

我希望组中包含1的所有成员显示整个组中的成员数量:

0 0 3 0
0 3 3 0
0 0 0 1

有没有任何已知方法如何找到它?我的意思是,我可能会为我需要的每个案例编写条件,因为我想将数字改为5以下,但这会很长。

2 个答案:

答案 0 :(得分:2)

使用Union-Find算法可以解决此问题。您的矩阵被解释为具有双向垂直和水平连接的非零节点的图形。然后问题是在跟踪分区大小的同时找到图的连接分区。这是一个独立的解决方案:

public class So21503628 {
    private List<List<Integer>> matrix;
    private int h, w;
    private Map<Integer, Node> nodes = new HashMap<>();
    So21503628() {
        matrix = new ArrayList<>();
        matrix.add(Arrays.asList(0,0,1,0));
        matrix.add(Arrays.asList(0,1,1,0));
        matrix.add(Arrays.asList(0,0,0,1));
        h = matrix.size(); w = matrix.get(0).size();
    }
    void run() {
        for (int y = 0; y < h; y++) {
            for (int x = 0; x < w; x++) {
                Node xy = nodeAt(x, y);
                if (xy == null) continue;
                Node x1y = nodeAt(x+1, y);
                if (x1y != null) union(xy, x1y);
                Node xy1 = nodeAt(x, y+1);
                if (xy1 != null) union(xy, xy1);
            }
        }
        for (int y = 0; y < h; y++) {
            for (int x = 0; x < w; x++) {
                Node n = nodeAt(x, y);
                if (n == null) continue;
                matrix.get(y).set(x, find(n).count);
            }
        }
        System.out.println(matrix);
    }
    Node nodeAt(int x, int y) {
        if (x >= w || y >= h || matrix.get(y).get(x) == 0) return null;
        int xy = y * w + x;
        Node node = nodes.get(xy); 
        if (node == null) { node = new Node(); nodes.put(xy, node); }
        return node;
    }
    void union(Node n1, Node n2) { // unite areas if separate
        Node r1 = find(n1), r2 = find(n2);
        if (r1 != r2) { r2.parent = r1; r1.count += r2.count; }
    }
    Node find(Node n) { // find representative + compress path
        Node r = n; while (r.parent != null) r = r.parent;
        if (r != n) while (n.parent != r) { Node h = n.parent; n.parent = r; n = h; }
        return r;
    }
    static class Node { Node parent; int count = 1; }
    public static void main(String[] args) { new So21503628().run(); }
}

Union-Find非常好(靠近O(n))。 有关Union-Find的详细信息,请参阅Wikipedia上的Disjoint-set data structure

答案 1 :(得分:1)

不知怎的,让我想起了MineSweeper。人们可以在这里轻松使用递归....

public class MatrixNeighborCount
{
    public static void main(String[] args)
    {
        int array[][] = new int[][]{
            { 0, 0, 1, 0 },
            { 0, 1, 1, 0 },
            { 0, 0, 0, 1 },
        };
        int result[][] = count(array);
        print(result);
    }

    private static void print(int array[][])
    {
        for (int r=0; r<array.length; r++)
        {
            for (int c=0; c<array[r].length; c++)
            {
                System.out.printf("%3d", array[r][c]);
            }
            System.out.println("");
        }
    }

    private static int[][] copy(int array[][])
    {
        int result[][] = new int[array.length][];
        for (int i=0; i<array.length; i++)
        {
            result[i] = array[i].clone();
        }
        return result;
    }

    private static int[][] count(int inputArray[][])
    {
        int result[][] = new int[inputArray.length][];
        for (int i=0; i<inputArray.length; i++)
        {
            result[i] = new int[inputArray[i].length];
        }

        int array[][] = copy(inputArray);
        for (int r=0; r<array.length; r++)
        {
            for (int c=0; c<array[r].length; c++)
            {
                if (array[r][c] == 1)
                {
                    int count = count(array, r, c);
                    distribute(inputArray, result, r, c, count);
                }
            }
        }
        return result;
    }

    private static int count(int array[][], int r, int c)
    {
        if (!valid(array, r, c)) return 0;
        if (array[r][c] == 0) return 0;

        array[r][c] = 0;
        return 1 + 
            count(array, r-1, c) +
            count(array, r+1, c) +
            count(array, r, c-1) +
            count(array, r, c+1);
    }

    private static void distribute(
        int inputArray[][], int result[][], int r, int c, int value)
    {
        if (!valid(inputArray, r, c)) return;
        if (inputArray[r][c] == 0) return;
        if (result[r][c] != 0) return;
        result[r][c] = value;
        distribute(inputArray, result, r-1, c, value);
        distribute(inputArray, result, r+1, c, value);
        distribute(inputArray, result, r, c-1, value);
        distribute(inputArray, result, r, c+1, value);
    }

    private static boolean valid(int array[][], int r, int c)
    {
        if (r < 0) return false;
        if (r >= array.length) return false;
        if (c < 0) return false;
        if (c >= array[r].length) return false;
        return true;
    }
}

但是

  1. 对于“大”数组,这将导致StackOverflowError
  2. 带有一些收藏的解决方案可能更优雅
  3. 如果您描述了您正在处理的实际数据结构,以及该程序的最终目的是什么,这可能会有所帮助....