Cracking the coding interview--Q20.12
2014-04-28 09:13
309 查看
题目
原文:
Given an NxN matrix of positive and negative integers, write code to find the submatrix with the largest possible sum.
译文:
给一个NxN的整数(每个格是正数、负数或零)矩阵,写代码找出具有最大和的子矩阵。
解答
分析如下(转自:hawstein)
暴力法,时间复杂度O(n6 )
最简单粗暴的方法就是枚举所有的子矩阵,求和,然后找出最大值。 枚举子矩阵一共有C(n, 2)*C(n, 2)个(水平方向选两条边,垂直方向选两条边), 时间复杂度O(n4 ),求子矩阵中元素的和需要O(n2 )的时间。
因此总的时间复杂度为O(n6 )。
部分和预处理,时间复杂度降到O(n4 )
上面的方法需要O(n2 )去计算子矩阵中元素的和。 这一部分我们可以在预处理的时候求出部分和,在使用的时候就只需要O(1) 的时间来得到子矩阵中元素的和。
![](http://hawstein.com/assets/img/2013/3/8/rect.png)
我们用一个二维数组p来保存矩阵的部分和,p[i][j]表示左上角是(1, 1),(下标从1开始), 右下角是(i, j)的矩阵中元素的和。这样一来,如果我们要求矩阵(x1, x2, y1, y2) 中元素的和(即上图矩阵D),我们可以通过以下式子计算得出:
只需要O(1)的时间。
部分和p[i][j]要怎么计算呢?我们可以通过更小的部分和来计算得到它:
其中A[i][j]是格子(i, j)中的整数。我们只需要O(n2 ) 的时间即可预处理得到所有的部分和。
降维,O(n3 )的解法
如果有一个一维的数组,我们要求它子数组之和的最大值,最好的时间复杂度是O(n)。 既然如此,我们可以把二维数组一个方向的数累加起来,将它变为一维数组,
然后就转化成了求一维数组子数组之和的最大值。看示意图:
在同一列中,我们把第i行到第j行的数加起来,得到如下:
这时候我们可以用O(n)的时候算出子数组之和的最大值,假设是第k个元素到第l 个元素的子数组。那么它实际上就对应二维数组中第i,j行,第k,l 列组成的子矩阵的元素和。
枚举i,j行需要O(n2 )的时间,求一维情况的子数组最大和需要O(n)的时间, 所以总的时间复杂度为O(n3 )。其中求第k列元素中,
第i行到第j行的元素和可以用部分和求解,仅需要O(1)的时间:
代码如下:(ctci)
---EOF---
原文:
Given an NxN matrix of positive and negative integers, write code to find the submatrix with the largest possible sum.
译文:
给一个NxN的整数(每个格是正数、负数或零)矩阵,写代码找出具有最大和的子矩阵。
解答
分析如下(转自:hawstein)
暴力法,时间复杂度O(n6 )
最简单粗暴的方法就是枚举所有的子矩阵,求和,然后找出最大值。 枚举子矩阵一共有C(n, 2)*C(n, 2)个(水平方向选两条边,垂直方向选两条边), 时间复杂度O(n4 ),求子矩阵中元素的和需要O(n2 )的时间。
因此总的时间复杂度为O(n6 )。
部分和预处理,时间复杂度降到O(n4 )
上面的方法需要O(n2 )去计算子矩阵中元素的和。 这一部分我们可以在预处理的时候求出部分和,在使用的时候就只需要O(1) 的时间来得到子矩阵中元素的和。
![](http://hawstein.com/assets/img/2013/3/8/rect.png)
我们用一个二维数组p来保存矩阵的部分和,p[i][j]表示左上角是(1, 1),(下标从1开始), 右下角是(i, j)的矩阵中元素的和。这样一来,如果我们要求矩阵(x1, x2, y1, y2) 中元素的和(即上图矩阵D),我们可以通过以下式子计算得出:
sum(D) = p[y2][x2] - p[y2][x1-1] - p[y1-1][x2] + p[y1-1][x1-1]
只需要O(1)的时间。
部分和p[i][j]要怎么计算呢?我们可以通过更小的部分和来计算得到它:
p[i][j] = p[i-1][j] + p[i][j-1] - p[i-1][j-1] + A[i][j]
其中A[i][j]是格子(i, j)中的整数。我们只需要O(n2 ) 的时间即可预处理得到所有的部分和。
降维,O(n3 )的解法
如果有一个一维的数组,我们要求它子数组之和的最大值,最好的时间复杂度是O(n)。 既然如此,我们可以把二维数组一个方向的数累加起来,将它变为一维数组,
然后就转化成了求一维数组子数组之和的最大值。看示意图:
第k列 第l列 第i行:... ... ... ... ... ... ... ... 第j行:... ... ... ...
在同一列中,我们把第i行到第j行的数加起来,得到如下:
第k列 第l列 只剩下一行:... ... ... ...
这时候我们可以用O(n)的时候算出子数组之和的最大值,假设是第k个元素到第l 个元素的子数组。那么它实际上就对应二维数组中第i,j行,第k,l 列组成的子矩阵的元素和。
枚举i,j行需要O(n2 )的时间,求一维情况的子数组最大和需要O(n)的时间, 所以总的时间复杂度为O(n3 )。其中求第k列元素中,
第i行到第j行的元素和可以用部分和求解,仅需要O(1)的时间:
sum(i,j,k) = p[j][k] - p[j][k-1] - p[i-1][k] + p[i-1][k-1]
代码如下:(ctci)
public static int getMaxMatrix(int[][] original) { int maxArea = Integer.MIN_VALUE; // Important! Max could be < 0 int rowCount = original.length; int columnCount = original[0].length; int[][] matrix = precomputeMatrix(original); for (int row1 = 0; row1 < rowCount; row1++) { for (int row2 = row1; row2 < rowCount; row2++) { for (int col1 = 0; col1 < columnCount; col1++) { for (int col2 = col1; col2 < columnCount; col2++) { maxArea = Math.max(maxArea, computeSum(matrix,row1, row2, col1, col2)); } } } } return maxArea; } private static int[][] precomputeMatrix(int[][] matrix) { int[][] sumMatrix = new int[matrix.length][matrix[0].length]; for (int i = 0; i < matrix.length; i++) { for (int j = 0; j < matrix.length; j++) { if (i == 0 && j == 0) { // first cell sumMatrix[i][j] = matrix[i][j]; } else if (j == 0) { // cell in first column sumMatrix[i][j] = sumMatrix[i - 1][j] + matrix[i][j]; } else if (i == 0) { // cell in first row sumMatrix[i][j] = sumMatrix[i][j - 1] + matrix[i][j]; } else { sumMatrix[i][j] = sumMatrix[i - 1][j] + sumMatrix[i][j - 1] - sumMatrix[i - 1][j - 1] + matrix[i][j]; } } } return sumMatrix; } private static int computeSum(int[][] sumMatrix, int i1, int i2, int j1, int j2) { if (i1 == 0 && j1 == 0) { // starts at row 0, column 0 return sumMatrix[i2][j2]; } else if (i1 == 0) { // start at row 0 return sumMatrix[i2][j2] - sumMatrix[i2][j1 - 1]; } else if (j1 == 0) { // start at column 0 return sumMatrix[i2][j2] - sumMatrix[i1 - 1][j2]; } else { return sumMatrix[i2][j2] - sumMatrix[i2][j1 - 1] - sumMatrix[i1 - 1][j2] + sumMatrix[i1 - 1][j1 - 1]; } }
---EOF---
相关文章推荐
- Cracking the coding interview--Q20.12
- 《Cracking the Coding Interview》——第18章:难题——题目12
- 《Cracking the Coding Interview》——第17章:普通题——题目12
- Cracking the coding interview--问题与解答
- Cracking the coding interview--Q3.1
- Cracking the coding interview--Q12.1
- 《Cracking the Coding Interview》——第2章:链表——题目6
- 《Cracking the Coding Interview》——第4章:树和图——题目7
- 《Cracking the Coding Interview》——第6章:智力题——题目3
- 《Cracking the Coding Interview》——第9章:递归和动态规划——题目5
- 程序员面试题目:Cracking the coding interview 分析与解答
- Cracking the coding interview--Q5.3
- Cracking the coding interview--Q5.6
- Cracking the coding interview--Q15.5
- Cranking The Coding Interview: 12
- Cracking The Coding Interview 1.1
- 【Cracking the coding interview】Q1.4(变位词)
- Cracking the coding interview--Q17.5
- Cracking the coding interview--Q18.3
- Cracking the Coding Interview Q1.3