LeetCode简易题解--053

题意简述:给定一个数组,这个数组有许多连续子集,每个子集的所有数字之和记为A,找出A的最大值。

例如,数组为[-2,1,-3,4,-1,2,1,-5,4],最大子集为:[4,-1,2,1],其和为6.

解法:动态规划

记录数组sums[]sums[i]表示从第0到第i个数字之和。则sums[i, j] = sums[i] - sums[j - 1], j < i
那么该问题则转化为找出sums[]中的最大差值,类似LeetCode第121题。

例如,对数组[-2,1,-3,4,-1,2,1,-5,4]sums[] = [-2,-1,-4,0,-1,1,2,-3,1],最大差值为2-(-4)=6

这个问题怎么求呢?
遍历数组,记录当前遇到的最小值min,数组中的每一个数都减去min,将该结果与当前记录的最大差值max比较决定是否更新max的值。遍历结束后max就是最大差值。

int min = nums[0];
int max = 0;
for (int i = 1; i < n; ++i) {
    if (nums[i] < min) min = nums[i];
    if (nums[i] - min > max) {
        max = nums[i] - min;
    }
}

但是这个方法不是万能的,有两种例外:

  1. 目标数组所有元素都为负数时。此时sums[]是降序排序的,因此min肯定是当前的值,这样便无法求出结果。例如,对数组[-1, -2]sums[] = [-1, -3]max始终为0.
  2. 最大子数组下标从0开始并且此最大子数组所有元素都为非负数。例如,对数组[1, 2, -1]sums[] = [1, 3, 2]。此时若按照以上的方法求,得出的结果为3 - 1 = 2,但实际上最大子数组却是[1, 2],结果为3。原因在于:sums[i, j] = sums[i] - sums[j - 1], j < i。此时,结果是sums[1, 0],表示从0号元素加到1号元素,但是,sums[j - 1] = sums[0 - 1] = sums[-1]是不存在的。

第一种情况的解决方法是,既然以上的方法不能处理sums[]是降序排序的情况,那么就对这种情况单独考虑:遍历找到数组中的最大值,这个最大值就是结果(所有元素都是负数,那么最大子数组只会有一个元素,就是数组中的最大值。

bool negative = true;
for (int i = 0; i < n; ++i) {
    if (nums[i] > 0) negative = false;
}
if (negative) {
    int max = INT_MIN;
    for (int i = 0; i < n; ++i)
        if (nums[i] > max) max = nums[i];
    return max;
}

第二种情况的解决方法是:既然sums[-1]是不能存在的,那么我们只要假设它存在就好了:将sums[]右移一位,第一位置为0,那么第1个元素加到第i个元素表示为sums[i+1]。例如,对数组[1, 2, -1]sums[] = [0, 1, 3, 2]。此时,sums[1, 0]的值应为sums[2] - sum[0] = 3,这样便得到了正确的结果。因此代码修改为:

vector<int> sums(n + 1, 0);
int max = 0;
int min = 0;
for (int i = 0; i < n; ++i) {
    sums[i + 1] = sums[i] + nums[i];
    if (sums[i + 1] < min) min = sums[i + 1];
    if (sums[i + 1] - min > max)
        max = sums[i + 1] - min;
}

最后总的代码为:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int n = nums.size();

        bool negative = true;
        for (int i = 0; i < n; ++i) {
            if (nums[i] > 0) negative = false;
        }
        if (negative) {
            int max = INT_MIN;
            for (int i = 0; i < n; ++i)
                if (nums[i] > max) max = nums[i];
            return max;
        }

        vector<int> sums(n + 1, 0);
        int max = 0;
        int min = 0;
        for (int i = 0; i < n; ++i) {
            sums[i + 1] = sums[i] + nums[i];
            if (sums[i + 1] < min) min = sums[i + 1];
            if (sums[i + 1] - min > max)
                max = sums[i + 1] - min;
        }
        return max;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值