給定一個由整數組成二維矩陣(r*c),如今須要找出它的一個子矩陣,使得這個子矩陣內的全部元素之和最大,並把這個子矩陣稱爲最大子矩陣。

題目描述

有一個正整數和負整數組成的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

相關文章
相關標籤/搜索