java - 如何在 Java 中查找子数组在二维数组中是否有特定的总和?

标签 java algorithm multidimensional-array dynamic-programming

我正在尝试通过比较源图像和图案图像中存在的像素的平均颜色来解决图像匹配问题。我已将此问题简化为子数组求和问题,但找不到解决方法。

假设我有一个所有正整数的二维数组 ARR。我有一个数字 x(这是小图案图像中像素颜色的平均值)。我只需要在 ARR 中找到任何具有精确总和 x 的子数组。我发现了一个类似的问题,可以在此处使用动态编程来解决。

http://www.geeksforgeeks.org/dynamic-programming-set-27-max-sum-rectangle-in-a-2d-matrix/

但是那是关于找到一个具有最大总和 的子数组,而不是已经给出的总和。

So if this the given array.

3   4   8   9   3
2   10  4   2   1
8   1   4   8   0
3   5   2   12  3
8   1   1   2   2

And if the given sum is 19, then it should return this window

3   4   8   9   3
2   10  4   2   1
8   1   4   8   0
3   5   2   12  3
8   1   1   2   2

And if the given sum is 23, then it should return this window

3   4   8   9   3
2   10  4   2   1
8   1   4   8   0
3   5   2   12  3
8   1   1   2   2
    

我怎样才能有效地找到它?这里可以使用动态规划吗?请帮帮我。

最佳答案

使用相同的原理,但针对更简单的问题。首先,我预先计算数组中每个的累积和,即 A[i][j] += A[i-1][j]。

然后,对于每对开始/结束行 (i1, i2),我将它们视为单个数组 B[j],这意味着 B[j] = A[i2][j] - A[i1- 1][j]。然后,我们需要找到具有精确总和的子数组。由于数组仅由正数组成,我可以在 O(n) 中找到它。

总的来说,这个算法是 O(n^3)。

对于您提供的值,我能够找到一些额外的数组:

对于目标 = 19:

Found between (0,0) and (1,1)
Found between (0,3) and (2,4)
Found between (0,2) and (4,2)
Found between (1,1) and (2,2)
Found between (1,2) and (2,4)
Found between (2,0) and (4,0)
Found between (3,3) and (4,5)

目标 = 23:

Found between (0,2) and (1,3)
Found between (0,3) and (2,4)
Found between (2,0) and (3,2)
Found between (2,3) and (3,4)
Found between (3,1) and (4,4)

我使用的代码:

public static void main(String[] args) {
    int[][] A = {
            {3, 4, 8, 9, 3},
            {2, 10, 4, 2, 1},
            {8, 1, 4, 8, 0},
            {3, 5, 2, 12, 3},
            {8, 1, 1, 2, 2},
    };

    int target = 19;

    for (int i = 1; i < A.length; i++)
        for (int j = 0; j < A[i].length; j++)
            A[i][j] += A[i - 1][j];


    for (int i1 = 0; i1 < A.length; i1++) {
        for (int i2 = i1 + 1; i2 < A.length; i2++) {
            int j1=0, j2=0, s=0;

            while(j2<A[i1].length) {
                while(s<target && j2<A[i1].length) {
                    s += A[i2][j2] - (i1 > 0 ? A[i1-1][j2] : 0);
                    j2++;
                    if (s==target)
                        System.out.println(String.format("Found between (%d,%d) and (%d,%d)", i1, j1, i2, j2-1));
                }
                while(s>=target) {
                    s -= A[i2][j1] - (i1 > 0 ? A[i1-1][j1] : 0);
                    j1++;
                    if (s==target)
                        System.out.println(String.format("Found between (%d,%d) and (%d,%d)", i1, j1, i2, j2));
                }
            }
        }
    }
}

关于java - 如何在 Java 中查找子数组在二维数组中是否有特定的总和?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15467855/

相关文章:

java - 单个生产者多个消费者 - 队列包含 null

c++ - 如何删除树的 child

java - 按边标签对顶点组的传入顶点进行分组

java - 如何在调用 dispose() 后重置 swing 中的字段

algorithm - 围绕一个圆绘制均匀大小的标签

algorithm - 为什么我在下面的问题中只迭代到 sqrt(N) ?

java - 如何使用用户输入在 Java 中填充二维数组?

jquery推送制作多维数组

c - C 中 2 种数据类型/MAP 的数组

java - Android - 执行任务,等待,什么都不做,然后再次执行任务?