【动态规划 - 最大子段和】环形子数组的最大和(Kadane算法+逆向思维)LEETCODE 918

引言

给一个环形的整数数组,求解最大的非空子数组和。

例题

【LEETCODE 918】

算法描述

先不考虑环的情况,那么将会是经典的最大子数组和的问题,特殊之处在于需要排除掉空数组的情况,用Kadane算法解决即可,这里不再赘述。

考虑环的情况,即最大子数组出现在头尾相接的数组中,这种情况应该如何解决呢?

这里可以用逆向思维来思考,如果最大子数组在头尾相接的数组中,那么就相当于从整个数组中“挖”掉了中间的最小子数组(不包含头尾元素),即最大子数组和转化为整个数组的和减去最小子数组和。按照这个思路,本题只需同时计算最大子数组和以及最小子数组和,比较两种情况下答案的大小即可。但需要考虑特殊情况,排除掉空数组,第一种情况比较容易处理,第二种情况需要判断最小子数组是否是整个数组。

可以通过最小子数组和是否等于整个数组之和来判断,如果等于则排除掉。证明这种判断方法的正确性,用反证法比较容易。考虑出现一个最小子数组等于整个数组之和的情况,如果它的左右不全为0,则左右数组之和为一正一负,最小子数组加上和为负的数组,数组和更小,与最小子数组矛盾,如果它的左右全为0,那么表示最大子数组和是0的情况可以取到,但这种情况已经在算最大子数组时包含到了,所以排除掉也无所谓。

代码实现

class Solution {
public:
    int maxSubarraySumCircular(vector<int>& nums) {
        int ans = 0, tot = 0;
        int minans = 0;
        int n = nums.size();
        int f, g; //f存储最大,g存储最小
        tot = ans = minans = f = g = nums[0];
        for (int i = 1; i < n; i++) {
            f = max(f, 0) + nums[i];
            ans = max(ans, f);
            g = min(g, 0) + nums[i];
            minans = min(minans, g);
            tot += nums[i];
        }
        if (minans != tot) {
            ans = max(ans, tot - minans);
        }
        return ans;
    }
};

评注

  1. Kadane算法可以优化空间到O(1),无需存储O(n)
  2. 本题用逆向思维去解决环的问题,可以作为一种特殊的处理环相关问题的参考思路
  3. 另外,反证法也是证明算法思路正确性的一种常见方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值