LeetCode 0053

来源:互联网 发布:知乎俄罗斯航空发动机 编辑:程序博客网 时间:2024/05/19 22:02

53.Maximum Subarray

原题链接

我的思路:

如果说,一个数组中的数都是负数或0。由于题目中说到,这个子序列至少包含一个数字。那么这时候,如果最大的子序列就是这个数列中最大的数。

如果这个数组是有正数也有负数的,那么就需要认真考虑一下了。先从只有一个数的情况开始考虑,此时不需要想,直接返回这个数就好了。如果有两个数,此时你显然会想着暴力枚举,因为就三种情况。那我们就把数字再加一个,变成a1,a2,a3 。此时暴力枚举的代价其实也不高,但是可以有一些优化。我们假设,a10 ,那么此时只需要考虑a2,a3 就好了。可能你看到这里会想,是不是用分治的思想。但是不是的,这里是用的动态规划。我们可以知道,如果一个数组是以负数开头的,那么除非这个数列的元素全都是负数,否则返回的子序列一定是以正数开头的。因为总可以去掉最开始的一个负数,使得总和变大。那么同理,最后也不会是以负数结尾。同样的道理,一些正数与一些负数的和如果小于0,那么我们也不需要。

我先给出动态规划的状态转移方程,之后再解释:dp[i]=max(dp[i1]+nums[i],0)

dp[i] 表示从0一直到i的方案中,以nums[i] 结尾的子序列可以得到的最大和。当然这里的描述略有不准确。

nums[i] 表示第i个数。

由于后面一定存在一个子序列,使得子序列和为正数,那么我就枚举以每个nums[i] 为结尾的子序列和。对于nums[i] 结尾的子序列和最大值,要么前面是正数,就可以加上去,要么是0/负数,就不取。此时在计算的时候就已经处理好了,没有放到后面去处理。

我的代码:

class Solution {public:    int maxSubArray(vector<int>& nums) {        auto max_num_ptr = max_element(nums.begin(), nums.end());        int max_num = *(max_num_ptr);        if(max_num < 0 ) {            return max_num;        }        int len = nums.size();        vector<int> dp(len, 0);        dp[0] = max(nums[0], 0);        for(int i = 1; i < len; i++) {            dp[i] = max(dp[i-1] + nums[i], 0);        }        auto max_sum_ptr = max_element(dp.begin(), dp.end());        return *max_sum_ptr;    }};

最快速度的代码:

class Solution {public:    int maxSubArray(vector<int>& nums) {        int maxSum = 0;        int res;        int currSum =0;        int maximum = nums[0];        for(int i=0;i<nums.size();i++)        {            currSum += nums[i];            maximum = max(maximum, nums[i]);            if(currSum<0)                currSum=0;            if(maxSum < currSum)            {                maxSum = currSum;            }        }        if(maxSum == 0)        {            return maximum;        }        return maxSum;    }};

应该说最快速度的代码,是比较符合我讲的思路的。