[LintCode] Continuous Subarray Sum II

Given an integer array, find a continuous rotate subarray 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 their are duplicate answer, return anyone. The answer can be rorate array or non- rorate array)

 Example

Give [3, 1, -100, -3, 4], return [4,1].

分析:

此题是Continuous Subarray Sum的升级版本。对于给定序列A, Continuous Subarray Sum中,子序列为A{i -> j}, 要求 0 <= i <= j < size(A),此为经典动态规划问题。在这里,子序列除了有之前的形式外,还允许rotate subarray,即子序列允许从尾部延续到头部,形式为A{0 -> i, j -> size(A) - 1}。

解法一:

因为允许尾部到头部形成子序列。通常的想法是把数据copy一份连到尾部。此时我们可以用Continous Subarray Sum的解法来做。但是有一点区别,我们的子序列长度不能超过size(A)。因此,我们依然可以用动态规划来做,不过需要考虑到序列的长度。为了实现简便,下面给出一个O(N^2) 非动态规划的解法,利用了累计数列和条件剪枝。不过最后三个数据还是会超时。

vector<int> continuousSubarraySumII(vector<int>& A) {
        // Write your code here
        vector<int> result(2, 0);
        int n = A.size();
        if(n < 2) return result;
        
     //duplicate array vector
<int> B(A); B.insert(B.end(), A.begin(), A.end());
//cumsum can help to calculate the sum from B(i) to B(j) with O(1) time vector
<int> cumsum; cumsum.push_back(B[0]); for(int i = 1;i < B.size();++i) cumsum.push_back(cumsum[i - 1] + B[i]); int maxVal = B[0], left = 0, right = 0; for(int s = 0;s < n;++s){ //there is no need to start from an negative number, this pruning is useful if(B[s] <= 0) continue; for(int e = s; e < s + n;++e){ int cur = 0; if(s == 0) cur = cumsum[e]; else cur = cumsum[e] - cumsum[s - 1]; if(cur > maxVal){ maxVal = cur; left = s; right = e; } } } result[0] = left%n; result[1] = right%n; return result; }

解法二:

进一步分析发现,第二种subarray其实和第一种是相关的。我们可以通过剪掉最小连续子序列得到第二种subarray。这里需要注意当所有数字为负的情况。

vector<int> continuousSubarraySumII(vector<int>& A) {
        // Write your code here
        vector<int> result(2, 0);
        int n = A.size();
        if(n < 2) return result;
        
        vector<int> posMax(n, 0), posMaxIdx(n, 0), posMin(n, 0), posMinIdx(n, 0);
        posMax[0] = A[0];
        posMin[0] = A[0];
        posMaxIdx[0] = 0;
        posMinIdx[0] = 0;
        int sum = A[0], maxVal = A[0], minVal = A[0], 
            maxL = 0, maxR = 0, minL = 0, minR = 0;
    
        for(int i = 1;i < n;++i){
            sum += A[i];
            //max subArray
            if(posMax[i - 1] > 0){
                posMax[i] = posMax[i - 1] + A[i];
                posMaxIdx[i] = posMaxIdx[i - 1];
            }else{
                posMax[i] = A[i];
                posMaxIdx[i] = i;
            }
            //min subArray
            if(posMin[i - 1] < 0){
                posMin[i] = posMin[i - 1] + A[i];
                posMinIdx[i] = posMinIdx[i - 1];
            }else{
                posMin[i] = A[i];
                posMinIdx[i] = i;
            }
            
            if(posMax[i] > maxVal){
                maxVal = posMax[i];
                maxL = posMaxIdx[i];
                maxR = i;
            }
            if(posMin[i] < minVal){
                minVal = posMin[i];
                minL = posMinIdx[i];
                minR = i;
            }
        }
        
        int val = sum - minVal;
        if(val <= maxVal || (minL == 0 && minR == n - 1)){
            result[0] = maxL;
            result[1] = maxR;
        }else{
            result[0] = minR + 1;
            result[1] = minL - 1;
        }
        
        return result;
    }
posted @ 2015-08-27 16:19  xchangcheng  阅读(629)  评论(0编辑  收藏  举报