1. 程式人生 > >動態規劃問題系列---連續子陣列(二維)的最大和

動態規劃問題系列---連續子陣列(二維)的最大和

題目1

一維陣列的連續子陣列的最大和
輸入一個整型陣列,數組裡有正數也有負數。陣列中一個或連續的多個整陣列成一個子陣列。求所有子陣列的和的最大值。要求時間負責度為O(n)。

分析

假如輸入陣列為{1,-2,3,10,-4,7,2,-5},我們嘗試從頭到尾累加其中的正數,初始化和為0,第一步加上1,此時和為1,第二步加上-2,此時和為-1,第三步加上3,此時我們發現-1+3=2,最大和2反而比3一個單獨的整數小,這是因為3加上了一個負數,發現這個規律以後我們就重新作出累加條件:如果當前和為負數,那麼就放棄前面的累加和,從陣列中的下一個數再開始計數

實現


public class
Num6 {
/** * @param args */ public static void main(String[] args) { int[] a={1,-2,3,10,-4,7,2,-5}; maxSum(a); } public static void maxSum(int[] a){ int maxSum=a[0]; int sum=a[0]; int start=0; int begin=0,end=0; for(int i=1
;i<a.length;i++){ if(sum<0){ sum=a[i]; start=i; }else{ sum+=a[i]; } if(sum>maxSum){ maxSum=sum; begin=start; end=i; } } System.out.println("maxSum="
+maxSum); for(int i=begin;i<=end;i++){ System.out.print(a[i]+" "); } } }

題目2

二維陣列的連續子陣列的最大和。
二維陣列的連續子陣列即為一個矩陣;
如下圖所示
這裡寫圖片描述
設矩陣的坐上頂點為A(i,j), 右下頂點為 B(endi, endj). 在圖中即為 A(1,1), B(3,3)。我們可以用Rect(A,B)即 (1,1,3,3,)來表示矩形區域。

方法1:直接計算

遍歷所有的矩形區域,找出其中的最大值,其中遍歷的話複雜度為O(M^2 * N^2),假設二維陣列為M行N列。
其中怎麼計運算元矩陣的和呢?通過預處理,我們可以再O(1)的時間內算出。具體看下面的程式碼:
arrSum函式即做預處理,得到陣列p,p[i][j]表示已Rect(0, 0, i-1, j-1)矩形區域的總和。有了p陣列就可以直接計算出任意矩形的總和。

//計算2維陣列的最大和子矩陣
    //直接計算:p[i][j]表示{0,0,i,j}的子矩陣的和;利用p可以快速求出sum{starti,startj,endi,endj}
    public static void max2Sum_1(int[][] a,int m,int n){
        int[][] p=new int[m+1][n+1];
        //計算p矩陣
        p[0][0]=0;
        for(int i=1;i<m;i++){
            p[i][0]=0;
        }
        for(int j=1;j<n;j++){
            p[0][j]=0;
        }
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++){
                p[i][j]=p[i-1][j]+p[i][j-1]+a[i-1][j-1]-p[i-1][j-1];
            }
        }

        for(int i=0;i<m+1;i++){
            for(int j=0;j<n+1;j++){
                System.out.print(p[i][j]+"\t");
            }
            System.out.println();
        }

        int si=0,sj=0,ei=0,ej=0;

        //遍歷所有子矩陣
        int ans=Integer.MIN_VALUE;
        for(int i=1;i<=m;i++){  //行  從0到m
            for(int j=1;j<=n;j++){    //列開始 從0到n
                for(int endi=i;endi<=m;endi++){    //行結束  從i到m
                    for(int endj=j;endj<=n;endj++){
                        int sum=p[endi][endj]-p[i-1][endj]-p[endi][j-1]+p[i-1][j-1];      //子矩陣:從i,j開始到endi,endj
                        if(sum>ans){
                            ans=sum;
                            si=i;
                            sj=j;
                            ei=endi;
                            ej=endj;
                            System.out.println(ans+"  "+si+" "+sj+" "+ei+" "+ej);
                        }
                    }
                }
            }
        }

        System.out.println(ans);
        System.out.println(si+" "+sj+" "+ei+" "+ej);

    }

方法2: 轉化為一維陣列計算

將每列中的各行相加,得到一個一維陣列,轉化求一維陣列的最大子陣列;
對矩陣,壓縮行,將每個子矩陣轉換化為一維陣列,進行求解;
子矩陣的高度:從1行到m行==所以需要遍歷所有的行;為減少遍歷的行數;==當m>n時,進行矩陣逆,

實現

    public static void max2Sum_2(int[][] a,int m,int n){
        if(m>n){
            a=reverse(a);
            int tmp=m;
            n=m;
            m=tmp;
        }

        //求出每一列中從第一行到第i行的和
        int[][] p=new int[m+1][n+1];
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++){
                p[i][j]=p[i-1][j]+a[i-1][j-1];
            }
        }

        //求每個子陣列的和
        int maxSum=Integer.MIN_VALUE;
        int sum=0;
        int si=0,sj=0,ei=0,ej=0;

        for(int h=1;h<=m;h++){     //子矩陣的高度
            for(int i=1;i+h-1<=m;i++){//子矩陣從i行開始,到endLine結束
                int endLine=i+h-1;
                sum=maxSum_2(p,i,endLine,n);
                if(sum>maxSum){
                    maxSum=sum;                 
                }
            }
        }

        System.out.println(maxSum);
    }

    //求一維陣列的最大子陣列
    private static int maxSum_2(int[][] p, int startLine, int endLine,int n) {
        int maxSum=p[endLine][1]-p[startLine-1][1];//初始化最大子陣列和為第一列的和;

        int sum=maxSum;

        for(int i=2;i<=n;i++){
            int num=p[endLine][i]-p[startLine][i];
            if(sum<0){
                sum=num;
            }else{
                sum+=num;
            }
            if(sum>maxSum){
                maxSum=sum;
            }
        }
        return maxSum;
    }

    private static int[][] reverse(int[][] a) {
        int m=a.length;
        int n=a[0].length;
        int[][] newArr=new int[n][m];
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                newArr[j][i]=a[i][j];
            }
        }
        return newArr;
    }

相關推薦

動態規劃_連續數組的

但是 == 向量 常常 ret pub num 負數 測試 題目描述 HZ偶爾會拿些專業問題來忽悠那些非計算機專業的同學。今天測試組開完會後,他又發話了:在古老的一維模式識別中,常常需要計算連續子向量的最大和,當向量全為正數的時候,問題很好解決。但是,如果向量中包含負數,是

動態規劃問題系列---連續陣列()的

題目1 一維陣列的連續子陣列的最大和 輸入一個整型陣列,數組裡有正數也有負數。陣列中一個或連續的多個整陣列成一個子陣列。求所有子陣列的和的最大值。要求時間負責度為O(n)。 分析 假如輸入陣列為{1,-2,3,10,-4,7,2,-5},我們嘗試從頭

動態規劃連續陣列

這個題目寫了不下三遍了,次次寫還次次想不起來,想起來也還寫好幾遍才能寫對,求一串陣列的最大最大子序列和,用動態規劃的方法,簡直不要太高效。 比如下面這個陣列{1,-2,3,10,-4,7,2,-5},最大連續子陣列是{3,10,-4,7,2}和為

陣列連續陣列之和的值(一

求陣列的連續子陣列之和的最大值 輸入一個N個元素的整型陣列,數組裡有正數也有負數。陣列中連續的一個或多個整陣列成一個子陣列,每個子陣列都有一個和。求所有子陣列的和的最大值。 例如輸入的陣列為-9  -3  -2  2  -1  2  5  -7  1  5,和最大的子陣列為

【LeetCode & 劍指offer刷題】動態規劃與貪婪法題4:42 連續數組的(53. Maximum Subarray)

offer pla style other res another () nor pro 【LeetCode & 劍指offer 刷題筆記】目錄(持續更新中...) 53. Maximum Subarray Given an integer array nu

連續數組的(基於動態規劃

動態 pty ostream style http 還要 clu ons 連續子數組 題目   輸入一個整型數組,數組裏有正數也有負數。數組中一個或連續的多個整數組成一個子數組。求所有子數組的和的最大值。要求時間復雜度為O(n)。例如輸入的數組為{1,-2,3,10,-4,

陣列連續陣列之和的

同一個問題:http://blog.csdn.net/witsmakemen/article/details/17740933    一個有N個整數元素的一維陣列{A[0],A[1],....,A[N

連續數組的

println 宋體 for 中間 原來 動態規劃法 family 元素 oid 方法一:舉例分析數組的規律   例如數組{1,-2,3,10,-4,7,2,-5}   分析:循環遍歷數組,初始累加和為0。第一步,和為1.第二步,和為-1;第三步,和小於0,如果用-1加上3

連續數組的

align div 置0 color 最大的 求解 for 技術分享 分享 一、題目:   這是一道考的爛的不能再爛的題目,但是依然有很多公司樂於將這樣的題目作為筆試或面試題,足見其經典。 問題是這樣的:一個整數數組中的元素有正有負,在該數組中找出一個連續子數組,要求該連

30連續數組的

for max 很好 例如 desc div 最大 今天 需要 題目描述 HZ偶爾會拿些專業問題來忽悠那些非計算機專業的同學。今天測試組開完會後,他又發話了:在古老的一維模式識別中,常常需要計算連續子向量的最大和,當向量全為正數的時候,問題很好解決。但是,如果向量中包含負

【劍指offer】42、連續數組的

class 分享 因此 eat 組成 連續 最大和 累加 ret 題目 輸入一個整型數組,數組裏有正數也有負數。數組的一個或連續多個整數組成一個子數組。求所有子數組的最大和。要求時間復雜度為O(n) 思路一 試著從頭到尾累加每個數字,若發現有子數組和小於零,則加上後面的數字

劍指offer-連續數組的

更新 ++ += 找到 最終 gin spa 計算機專業 gre 題目:連續子數組的最大和 題目描述:HZ偶爾會拿些專業問題來忽悠那些非計算機專業的同學。今天測試組開完會後,他又發話了:在古老的一維模式識別中,常常需要計算連續子向量的最大和,當向量全為正數的時候,問題

python實現連續數組的

http tom 測試 mathjax 治法 bottom reat 所有 title 題目描述 HZ偶爾會拿些專業問題來忽悠那些非計算機專業的同學。今天測試組開完會後,他又發話了:在古老的一維模式識別中,常常需要計算連續子向量的最大和,當向量全為正數的時候,問題很好解決

劍指offer--43.連續數組的

color pub 時間限制 scribe 返回 col coder 但是 mut 最大子段和,最大能取所有 ---------------------------------------------------------------- 時間限制:1秒 空間限制:32

連續陣列

    演算法導論中的一個題目,上次面試題中被擴充套件到了二維和二維環形陣列,記錄下以供參考。一、    一維連續子陣列 最大和    問題描述:給定一個一維陣列,求其中連續子陣列和的最大值。    樣

《劍指offer》系列 連續陣列(Java)

連結 牛客:連續子陣列的最大和 題目描述 HZ偶爾會拿些專業問題來忽悠那些非計算機專業的同學。今天測試組開完會後,他又發話了:在古老的一維模式識別中,常常需要計算連續子向量的最大和,當向量全為正數的時候,問題很好解決。但是,如果向量中包含負數,是否應該包含某個負數,並期望旁邊

《劍指offer》系列 連續陣列(Java)

連結 題目描述 HZ偶爾會拿些專業問題來忽悠那些非計算機專業的同學。今天測試組開完會後,他又發話了:在古老的一維模式識別中,常常需要計算連續子向量的最大和,當向量全為正數的時候,問題很好解決。但是,如

Java實驗——輸出數組連續數組的

http ring list static main 整理 右下角 只需要 image 該算法思路,根據我博客裏面一維子數組求和的思路,可以用一個新的二維數組對該二維區域的數組進行求和,例如新的二維數組的第5個位置,就代表從1到5斜對角線的塊狀區域的和,即1,2,4,

一個整形陣列中有正數也有負數,陣列連續一個或多個組成陣列,每個子陣列都有一個,求所有陣列中和的

本文只作為學習筆記,如若侵權請告知,一定及時刪除 題目 輸入一個整型陣列,數組裡有正數也有負數。陣列中一個或者連續的多個整陣列成一個字陣列。求所有字陣列的和的最大值。要求時間複雜度為O(n)。例

程式設計之美8:求陣列陣列之和的

1: int MaxSum(int *A, int n) { int maximum = -INF; int sum; for (int i = 0; i < n; i++) { sum = 0; for (int j = i;