Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/140.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 高效地计算矩阵中元素的总和_Algorithm_Matrix - Fatal编程技术网

Algorithm 高效地计算矩阵中元素的总和

Algorithm 高效地计算矩阵中元素的总和,algorithm,matrix,Algorithm,Matrix,在一次采访中,有人问我是否有一个n*m矩阵,如何计算给定子矩阵(由左上角和右下角坐标定义)中的值之和 我被告知我可以预处理矩阵 我被告知矩阵可能是巨大的,子矩阵也可能是巨大的,所以算法必须是有效的。我有点结巴,没有人告诉我最好的答案 有人有好的答案吗?这应该行得通。你总是要通过子矩阵中的每个元素来做加法,这是最简单的方法 *请注意,以下代码可能无法编译,但它在伪代码中是正确的 struct Coords{ int x,y; } int SumSubMatrix(Coords topl

在一次采访中,有人问我是否有一个n*m矩阵,如何计算给定子矩阵(由左上角和右下角坐标定义)中的值之和

我被告知我可以预处理矩阵

我被告知矩阵可能是巨大的,子矩阵也可能是巨大的,所以算法必须是有效的。我有点结巴,没有人告诉我最好的答案


有人有好的答案吗?

这应该行得通。你总是要通过子矩阵中的每个元素来做加法,这是最简单的方法

*请注意,以下代码可能无法编译,但它在伪代码中是正确的


struct Coords{
    int x,y;
}

int SumSubMatrix(Coords topleft, Coords bottomright, int** matrix){
    int localsum = 0;
    for( int i = topleft.x; i <= bottomright.x; i++ ){
        for(int j = topleft.y; j <= bottomright.y; j++){
            localsum += matrix[i][j];
        }
    }
    return localsum;
}

现在,要么是O(n)要么是O(m)

创建一个新矩阵,其中entry
(i,j)
是原始矩阵中具有较低或等于
i
j
的元素的总和。然后,为了求子矩阵中元素的和,您可以使用和矩阵的子矩阵的角点进行常量的基本运算

特别是,找到求和矩阵的左上角、左下角、右上角和右下角,其中前三个位于子矩阵的外部,右下角位于子矩阵的内部。那么,你的总数是

bottom_right + top_left - bottom_left - bottom_right

这就是求和面积表的用途

您的“预处理”步骤是构建一个相同大小的新矩阵,其中每个条目都是该条目左上角的子矩阵之和。任何任意子矩阵和都可以通过查找和混合SAT中的4个条目来计算

编辑:下面是一个示例

对于初始矩阵

0 1 4
2 3 2
1 2 7
SAT是

0 1 5
2 6 12
3 9 22
SAT是使用S(x,y)=a(x,y)+S(x-1,y)+S(x,y-1)-S(x-1,y-1)获得的

其中S是SAT矩阵,a是初始矩阵


如果你想要右下角2x2子矩阵的和,答案是22+0-3-5=14。这显然与3+2+2+7相同。不管矩阵的大小如何,子矩阵的和可以在4次查找和3次算术运算中找到。构建SAT是O(n),同样地,每个单元只需要4次查找和3次数学运算。

下面是一个用C语言实现的示例,使用了上面一个答案中解释的面积汇总表概念

同样的Python实现可以在下面的链接中找到-

#包括
int pre[3][3];
int arr[3][3]={
{0,1,4},
{2,3,2},
{1,2,7}
};
void预处理()
{
对于(int i=0;i0)
{
pre[i][j]=arr[i][j]+pre[i-1][j]+pre[i][j-1]-pre[i-1][j-1];
}
else如果(i>0&&j==0)
{
pre[i][j]=arr[i][j]+pre[i-1][j];
}
else如果(j>0&&i==0)
{
pre[i][j]=arr[i][j]+pre[i][j-1];
}
其他的
{
pre[i][j]=arr[i][j];
}                    
}
}
}
整数子集合(整数x1、整数y1、整数x2、整数y2)
{
预处理();
int ans=pre[x2][y2]-pre[x1-1][y2]-pre[x2][y1-1]+pre[x1-1][y1-1];
返回ans;
}
int main()
{            
printf(“%d\n”,subsum(1,1,2,2));
返回0;
}

您可以通过动态编程来实现。创建大小为n*m的矩阵dp。 对于每个i,j,在哪里

1 <= i <= n , 1 <= j <= m 
dp[i][j] will be : 

dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + values[i][j]
看图片,了解算法是如何工作的

OD = dp[rx][ry], OB = dp[lx - 1][ry], OC = dp[rx][ly - 1], OA = dp[lx - 1][ly - 1]

矩阵是稀疏的吗?@Moron每个节点都包含子节点和的四叉树支持相对简单的更新,但不像Alan的简单回答那样容易求和。@Moron:问题以“在采访中我被问到”开始。所以,不,不是作业,除非存在作业以某种方式由面试组成的情况……矩阵可以是稀疏的或密集的,他提到它在任何情况下都需要工作。在这种情况下,我的误解在于什么是“预处理”。无论发生什么情况,您仍然需要相同数量的添加。我知道这种方法什么时候有用,但问题没有提供关于问题背景的进一步信息。实际上没有背景,只是要求加法比简单的循环和加法更快。建议进行预处理,但未达到使用大量内存或存储的程度(例如,对每个可能的矩阵进行预求和,并将其存储在x/y索引中)。+1表示正确答案。我以前从没听说过。我会用四叉树脱口而出一些东西,但这要好得多。这是面试中的琐事,除非他们想要知道(或声称知道)使用它的特定算法的人。谢谢艾伦!我从来没有听说过总面积表,我已经编程18年了。虽然我在大学里一直在睡觉/喝酒(我的坏习惯)。我已经使用这个想法好几年了,也从来没有听说过“汇总面积表”这个名字——维基百科上写得很差的一篇文章表明,它是计算机视觉/图形领域特有的一个名字。不过,对于熟悉动态编程的人来说,这个想法本身是相当自然的——也许太自然了,不配有一个名字。如果你不相信这一点,请参阅我的最新答案。这是关于算法的简单介绍。这就是为什么StackOverflow的算法部分绝对是最有趣的。你每天都在学习新概念。。但愿我能记住它们。你能告诉我这是怎么回事吗?亚群(1,1,2,2));那些数字是多少?1,1,2,2?这是演示该算法的最佳方式!谢谢这正是我需要的!
0 1 4
2 3 2
1 2 7
0 1 5
2 6 12
3 9 22
#include<stdio.h>

int pre[3][3];

int arr[3][3] = {
                {0,1,4},
                {2,3,2},
                {1,2,7}
                };

void preprocess()
{
    for(int i=0;i<3;i++)
    {
        for(int j=0;j<3;j++)
        {
            if(i>0 && j>0)
            {
                 pre[i][j] = arr[i][j] + pre[i-1][j] + pre[i][j-1] - pre[i-1][j-1];
            }
            else if(i>0 && j==0)
            {
                pre[i][j] = arr[i][j] + pre[i-1][j];
            }
            else if(j>0 && i==0)
            {
                pre[i][j] = arr[i][j] + pre[i][j-1];
            }
            else
            {
                pre[i][j] = arr[i][j];
            }                    
        }
    }
}

int subsum(int x1, int y1, int x2, int y2)
{
    preprocess();

    int ans = pre[x2][y2] - pre[x1-1][y2] - pre[x2][y1-1] + pre[x1-1][y1-1];
    return ans;
}

int main()
{            
    printf("%d\n",subsum(1,1,2,2));
    return 0;
}
1 <= i <= n , 1 <= j <= m 
dp[i][j] will be : 

dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + values[i][j]
1 ≤ lxi ≤ rx ≤ n, 1 ≤ ly ≤ ry ≤ m

sum = dp[rx][ry]  - dp[lx - 1][ry] - dp[rx][ly - 1] + dp[lx-1][ly - 1]
OD = dp[rx][ry], OB = dp[lx - 1][ry], OC = dp[rx][ly - 1], OA = dp[lx - 1][ly - 1]