leetcode第53题——最大子序和

题目:

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6

初次拿到这个题目,最直接的想法是:遍历整个数组,求其所有的子序列,然后找最大的。其大致思路自然是用两个索引i,j,然后获取i,j之间的数组的值,然后用打擂台法获取最大的;这种方法的时间复杂度是o(n^2)。

有没有更好的办法?或者说我们能不能找到一种策略,使得下一次的结果一定比上次大,这样我们只需要遍历一次数组就可以?

当然有,这种思想就是:如果当前序列和为负数,那么下一个寻找开始的位置。就不再包含当前位置及以前位置的数,!

我们借助这个思想分析一下上述示例数组:[-2,1,-3,4,-1,2,1,-5,4],

 1 第一次:当前序列和sum = -2<0;因此不再考虑位置0的数
 2 第二次:当前序列和sum = 1  >0;则当前最大和max_sum = 1;考虑位置1的数
 3 第三次:当前序列和sum = 1+-3 = -2<0;因此不再考虑-3以前的数;
 4 第四次:当前序列和sum = 4>0;则当前最大和sum_max = 4;此时最大序列为4;
 5 第五次:当前序列和sum = 4+-1=3>0;则当前最大和sum_max = 4;此时最大序列为4;但由于sum>0,我们仍然需要考虑将4作为起始点
 6 第六次:当前序列和sum = 4+-1+2 = 5>0;当前最大序列和sum_max = 5;此时最大序列[4,-1,2];
 7 第七次:当前序列和sum = 4+-1+2+1 = 6>0;当前最大序列和sum_max = 6;此时最大序列[4,-1,2,1];
 8 第八次:当前序列和sum =  4+-1+2+1 +-5 = 1>0;sum_max = 6;此时最大序列[4,-1,2,1];
 9 第九次:当前序列和sum =  4+-1+2+1 +-5+4 = 5>0;sum_max = 6,此时最大序列为
10 [4,-1,2,1];
11 结束!

就这样,当我们遍历完数组的时候,最大子序列就找到了;可见时间复杂度是O(n);

在这里有人也许会问:上述只是从位置3的元素4遍历到了结尾。会不会存在从位置3后面开始,到某个位置的数比从元素4开始的序列[4,-1,2,1]序列和更大?

显然不会,为何?因为我们说过,只要当前序列和<0,我们就舍弃之前所有的位置;而序列和>0,我们就保留那些位置。因此,我们保留了从4开始的位置。说明了序列和是大于0的;而从4后面开始,显然是从4开始的序列的子集,其和不可能大于从4开始。

那么上述思路有一个明显的漏洞是:如果当前序列和为负数,从下一个位置开始,不再包含当期所有位置;显然如果数组所有元素都是负数。那么我们最终是找不到一个最大和子序列的;但是我们知道如果一个序列全是负数,最大子序列就是其中最大的负数,因此,我们应该单独考虑全为负数的情况。

那么我们怎么考虑一个数组全部为负数呢?很简单,如果一个数组的最大元素为负数,那么整个数组就为负数。因此,我们可以给出完整的求最大子序列的代码:

 1 class Solution {
 2 public:
 3     int maxSubArray(vector<int>& nums) {
 4         int max = 0,temp = 0;
 5         int allnegative_max = nums[0];
 6     for (int i = 0; i < nums.size(); i++) {
 7         temp += nums[i];
 8         if (temp < 0)
 9             temp = 0;
10         if (max < temp)
11             max = temp;
12         if(nums[i] > allnegative_max)
13            allnegative_max = nums[i];//用于判断是否全部为负数
14     }
15     if(allnegative_max < 0)//说明数组全部为负数
16       return allnegative_max;
17     else
18     return max;
19     }
20 };

当然了,这个题目可以进一步的提问:找到最大和子序列的起始位置?那么又该如何编码呢?

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int max = 0,temp = 0;
        int start1,start2;
        int allnegative_max = nums[0];
    for (int i = 0; i < nums.size(); i++) {
        temp += nums[i];
        if (temp < 0)
        {
            temp = 0;
            start1 = i+1;
        }
        if (max < temp)
            max = temp;
        if(nums[i] > allnegative_max)
        {
           allnegative_max = nums[i];//用于判断是否全部为负数
           start2 = i;
        }
    }
    if(allnegative_max < 0)//说明数组全部为负数
      return allnegative_max;
    else
    return max;
    }
};

其中start1和start2表明了位置

原文地址:https://www.cnblogs.com/shaonianpi/p/12736005.html