最大字段和问题:

问题描叙:

给定由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,不完善的地方还请大家提出,互相进步。

谢谢观看