最大字段和問題:
問題描敘:
給定由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,不完善的地方還請大家提出,互相進步。