有一個正整數和負整數組成的NxN矩陣,請編寫代碼找出元素總和最大的子矩陣。請嘗試使用一個高效算法。算法
給定一個int矩陣mat和矩陣的階數n,請返回元素總和最大的子矩陣的元素之和。保證元素絕對值小於等於100000,且矩陣階數小於等於200。數組
測試樣例:測試
[[1,2,-3],[3,4,-5],[-5,-6,-7]],3
返回:10spa
/*思路: 1.求子矩陣的最大和,首先得斷定全部可能的子矩陣(縱向選定) 2.縱向選定後,將這塊子矩陣按行累加壓縮成一維,而後處理簡單的一維(橫向選定) 3.過程當中有最大值出現即時更新便可 */ public class SubMatrix { public int sumOfSubMatrix(int[][] mat, int n) { int maxSum = Integer.MIN_VALUE; int sum[] = new int[mat[0].length]; for(int i=0; i<mat.length; i++){//壓縮的起點 for(int j=0; j<sum.length; j++) sum[j]=0;//每次更換起點sum就重置,感受還可改進 for(int t=0; t<mat.length-i; t++){//步長,矩陣=起點+步長 for(int j=0; j<sum.length; j++) sum[j]+=mat[i+t][j];//求上述矩陣的壓縮和 maxSum = Math.max(maxSum, getMaxSum(sum)); //壓縮爲一維求和,取最大值 } } return maxSum; } public int getMaxSum(int a[]){//經常使用,一維數組中連續子數組的最大和int maxSum = Integer.MIN_VALUE; int curSum = 0; for(int i=0; i<a.length; i++){ curSum += a[i]; maxSum = Math.max(maxSum, curSum); if(curSum<0) curSum=0; } return maxSum; } }
或者:.net
public int maxSubMatrix(int[][] mat, int n) { // write code here /* * 法1.窮舉 * 法2.貪心法 * 首先設置子矩陣的列數,獲得二維矩陣row[][], * 其中row[i][j]表示第i行的第j列開始到j+row_len-1列的加和 * 對row[i][j]的每一列進行一維數組的最大序列和的計算,複雜度O(n) * 最大序列和計算方式見q17_8 * 所以最終複雜度爲0(n^3) */ int max = 0; for(int row_len = n; row_len >= 1; row_len--){ int[][] row = new int[n][n-row_len+1]; for(int i = 0; i <= n-1; i++){ for(int j = 0; j<= n-row_len; j++){ row[i][j] = cal(mat, j, i, row_len); } } //求每一個一維子矩陣中的最大序列和 for(int i = 0; i < n-row_len+1; i++){ int sum = 0; for(int j = 0; j < n; j++){ sum += row[j][i]; if(sum < 0){ sum = 0; }else if(sum > max){ max = sum; } } } } return max; } private int cal(int[][] mat, int start, int row_num, int len){ int cols = mat[0].length; int sum = 0; for(int i = start; i <= start+len-1; i++){ if(i < cols){ sum += mat[row_num][i]; } } return sum; }
問題描述:code
給定一個由整數組成二維矩陣(r*c),如今須要找出它的一個子矩陣,使得這個子矩陣內的全部元素之和最大,並把這個子矩陣稱爲最大子矩陣。
例子:
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
其最大子矩陣爲:blog
9 2
-4 1
-1 8
其元素總和爲15。get
假設最大子矩陣的結果爲從第r行到k行、從第i列到j列的子矩陣,以下所示(ari表示a[r][i],假設數組下標從1開始):
| a11 …… a1i ……a1j ……a1n |
| a21 …… a2i ……a2j ……a2n |
| . . . . . . . |
| . . . . . . . |
| ar1 …… ari ……arj ……arn |
| . . . . . . . |
| . . . . . . . |
| ak1 …… aki ……akj ……akn |
| . . . . . . . |
| an1 …… ani ……anj ……ann |it
那麼咱們將從第r行到第k行的每一行中相同列的加起來,能夠獲得一個一維數組以下:
(ar1+……+ak1, ar2+……+ak2, ……,arn+……+akn)
由此咱們能夠看出最後所求的就是此一維數組的最大子斷和問題,到此咱們已經將問題轉化爲上面的已經解決了的問題了。ast
一、若是沒有最大子段和問題的基礎,最直接的辦法,窮舉法,對二維矩陣中全部子矩陣進行計算求得最大值,時間複雜度爲(O(n^2*n^2));
二、基於最大子段和問題,算出任意n行的和數組,轉變成最大字段和進行處理,對於任意n行,若是採用各個處理的話,其時間複雜度相對較高,因此對和數組的處理是本題的又一關鍵;
三、壓縮矩陣
下面舉一個簡單的例子。在一個一維的數列中,要想求從第i個元素到第j個元素的和,咱們能夠用這樣的方法:設數組sum[i]表示從第1個到第i個元素的和,則:求從第i個元素到第j個元素的和,只需用sum[j]-sum[i]就足夠了。由此推廣到二維矩陣,設sum[i,j]表示矩陣第j列前i個元素的和,cost[i,j]表示原始數據,則:
for i:=1 to n do
for j:=1 to m do
sum[i,j]:=sum[i-1,j]+cost[i,j];
下一個問題是,如何將數據從壓縮的數組中讀出。
讀取數據代碼爲:
for i:=0 to n-1 do
for j:=i+1 to n do
for k:=1 to n do temp[k]:=sum[j,k]-sum[i,k];
到此,最大子矩陣問題就徹底轉換爲連續最大和問題。
參考:http://blog.csdn.net/zhanxinhang/article/details/6731134