LintCode 403. Continuous Subarray Sum II (循环数组经典题)

  1. Continuous Subarray Sum II

Given an circular integer array (the next element of the last element is the first element), find a continuous subarray in it, where the sum of numbers is the biggest. Your code should return the index of the first number and the index of the last number.

If duplicate answers exist, return any of them.

Example
Example 1:

Input: [3, 1, -100, -3, 4]
Output: [4, 1]
Example 2:

Input: [1,-1]
Output: [0, 0]
Challenge
O(n) time

这题如果没有想到正确思路的话很难。
我开始的想法还是基于Continuous Subarray Sum求出从0到2n-1的长度<=n的最大非空子数组,但是试了一下不容易。关键是这里添加了一个条件长度<=n。
比如说输入数组为[3,1,-3,4],扩展后得到[3,1,-3,4,3,1,-3,4]。如果不加长度限制,显然整个长度为8的整个数组就是最大非空子数组。但加了长度限制后,应该是[4,3,1]为最大非空子数组。但是到4的时候,sum>0,很难确定要从4开始。另一种办法是用2重循环,i=0…n, j=1…n,但是会超时。

解法1:
思路如下(参考九章): 先按照Continuous Subarray Sum求出无环情况下的最大非空子数组和S1。再用类似方法求出无环情况下的最小非空子数组和S2。答案即为max{S1, total_sum – S2}
注意:

  1. 特殊情况:如果选择了最小非空子数组而它是整个数组,说明所有A[i]都是负数,那么选取最大的A[i],其在求S1的时候就已经得到。
    代码如下:
class Solution {
public:
    /*
     * @param A: An integer array
     * @return: A list of integers includes the index of the first number and the index of the last number
     */
    vector<int> continuousSubarraySumII(vector<int> &A) {
        int n = A.size();
        if (n == 0) return vector<int>();
        
        int sum = A[0], maxSum = A[0], minSum = A[0], totalSum = A[0];
        int maxStartIndex = 0, maxEndIndex = 0;
        int gMaxStartIndex = 0, gMaxEndIndex = 0;
        int minStartIndex = 0, minEndIndex = 0;
        int gMinStartIndex = 0, gMinEndIndex = 0;
        
        for (int i = 1; i < n; ++i) {
            totalSum += A[i];
            if (sum < 0) {
                sum = A[i];
                maxStartIndex = i;
                maxEndIndex = i;
            } else {
                sum += A[i];
                maxEndIndex = i;
            } 
                
            if (sum > maxSum) {
                maxSum = sum;
                gMaxStartIndex = maxStartIndex;
                gMaxEndIndex = maxEndIndex;
            }
        }
        
        sum = A[0];
        for (int i = 1; i < n; ++i) {
            if (sum > 0) {
                sum = A[i];
                minStartIndex = i;
                minEndIndex = i;
            } else {
                sum += A[i];
                minEndIndex = i;
            }
            
            if (sum < minSum) {
                minSum = sum;
                gMinStartIndex = minStartIndex;
                gMinEndIndex = minEndIndex;
            }
        }
        
        if (maxSum > totalSum - minSum) {
            return vector<int>{gMaxStartIndex, gMaxEndIndex};
        } else {
            if (gMinStartIndex == 0 && gMinEndIndex == n - 1) {
                int maxElem = INT_MIN;
                int maxElemIndex = 0;
                for (int i = 0; i < n; ++i) {
                    if (maxElem < A[i]) {
                        maxElem = A[i];
                        maxElemIndex = i;
                    }            
                }
                return vector<int>{maxElemIndex, maxElemIndex};
                
            } else {
                return vector<int>{(gMinEndIndex + 1) % n, (gMinStartIndex - 1 + n) % n};
            }
        }       
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值