我有一个对象数组,其枚举为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以下,但这会很长。
答案 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;
}
}
但是:
如果您描述了您正在处理的实际数据结构,以及该程序的最终目的是什么,这可能会有所帮助....