動態規划之求解最大字段和


最大字段和問題:

問題描敘:

給定由N個整數組成的序列(a1,a2,...,an),求該序列字段和的最大和。

問題很簡短,做起來也不是很難,這里我們主要為了了解這么一種算法思想,然后再嘗試求解其他變種問題。

思路:

設最大字段和為X,
X=max(a[i]+···+a[j]),0<=i,j<=n;//為某一子段之和

我們該如何選出這段子段:
我們設m[j]為從0到j之間的最大子段和,0<=j<=n;
m[j]的含義就是:以a[j]為結束元素的連續數組的最大子段和。
由此,X=max(m[0]···m[n]);

下面求m[j]:

1.當m[j-1]>0時,無論a[j]為何值,
m[j]=m[j-1]+a[j];

2.當m[j-1]<=0時,無論a[j]為何值,
m[j]=a[j];

自己想的解釋:如果當前和為負數,會影響后續最大和,就像你站在地上和桌子上最終高度不同一樣,雖為相同高度,但產生的效果不同,也就是上一和為負數時,會影響當前正數發揮最大作用。
有點玄學了,**如果大佬有更好解釋歡迎指點。**

舉例:

k:    1    2    3    4
a:    3   -4    2    10
m:    3   -1    2    12

代碼:

int m[n+1];
b[1]=a[1];
int maxSum=a[1];
for(int i=2;i<=n;i++){
   if(m[i-1]<=0){
     m[i]=a[i];
    }
    else{
    m[i]=m[i-1]+a[i];
    }
   maxSum=max(m[i],maxSum);
}

最大子段和擴展:

原題在這

給定一個正整數和負整數組成的 N × M 矩陣,編寫代碼找出元素總和最大的子矩陣。

返回一個數組 [r1, c1, r2, c2],其中 r1, c1 分別代表子矩陣左上角的行號和列號,r2, c2 分別代表右下角的行號和列號。若有多個滿足條件的子矩陣,返回任意一個均可。

示例:

輸入:
[
   [-1,0],
   [0,-1]
]
輸出: [0,1,0,1]
解釋: 輸入中標粗的元素即為輸出所表示的矩陣

說明:

1 <= matrix.length, matrix[0].length <= 200

這最大子段和的思路去思考:

與之前不同的是之前單單只需考慮一條直線的數,但矩陣是有長和寬的,不過可以先試着去想:

要求0~M之間的最大矩陣和,可以先求0~j之間的最大矩陣和,0<=j<=n,最后再取最大值。
             當前范圍        
0  1  -1  0    <-0
1  2  -1  3
1 -1   0  4    <-2
2  1   3 -1

要求一個矩陣和,我們可以把豎直方向上的數放入一個數組中sumarr (范圍:0~N),這樣就轉換為了一個**最大子段和**,如上圖:

sumarr[0]  sumarr[1]   sumarr[2]  sumarr[3]

0+1+1       1+2+(-1)   -1+(-1)+0    0+3+4

然后就是套用最大子段和了,sumarr就相當於a[].

代碼實現:

vector<int> getMaxMatrix(vector<vector<int>>& matrix) {
        int tt = 0, tl = 0, bb = 0, br = 0, gmax = INT_MIN;
        for (int i = 0; i < matrix.size(); ++i) {
            vector<int> sumarr(matrix[0].size(), 0); // 對每個起始行i,創建一個對應的sumarr數組,初始置0
            for (int j = i; j < matrix.size(); ++j) {
                int m = 0, curmax = INT_MIN;
                for (int k = 0; k < matrix[0].size(); ++k) { 
                    sumarr[k] += matrix[j][k];      // 加和當前行當前位的值到sumarr數組中。
                    if (curmax <= 0) {              // 對sumarr[0,k]數組求最大字段和
                        m = k;                      // curmax<=0,說明以sumarr[k]結尾的最大字段和起點為自己
                        curmax = sumarr[k];
                    } else {
                        curmax += sumarr[k];
                    }
                    if (curmax > gmax) {            // 當curmax大於gmax時,更新tt,tl,bb,br
                        gmax = curmax;
                        tt = i;
                        tl = m;
                        bb = j;
                        br = k;
                    }
                }
            }
        }
        return {tt, tl, bb, br};
    }

代碼與解釋有點出入,但思路是一樣的,參考leetcode,不完善的地方還請大家提出,互相進步。

謝謝觀看


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM