一尘不染

最长阳性子阵列

algorithm

数组A []仅包含“ 1”和“ -1”

构造数组B,其中B [i]是从j开始到i为止的最长连续子数组的长度,其中 j < i and A[j] + .. + A[i] > 0

显而易见的O(n ^ 2)解决方案是:

for (int i = 0; i < A.size(); ++i) {
    j = i-1;
    sum = A[i];
    B[i] = -1; //index which fills criteria not found
    while ( j >=0 ) {
        sum += A[j];
        if (sum > 0)
            B[i] = i - j + 1;
        --j;
    }
}

我正在寻找O(n)解决方案。


阅读 178

收藏
2020-07-28

共1个答案

一尘不染

诀窍是要认识到,我们只需要找到的最小值j即可(A[0] + ... + A[j-1]) == (A[0] + ... + A[i]) - 1
A[j] + ... + A[i]与相同(A[0] + ... + A[i]) - (A[0] + ... + A[j-1]),因此一旦找到合适的j,j和i之和将为1。任何更早的j都不会产生正值,任何后来的j都不会给我们最长的序列。如果我们跟踪第一次到达每个连续负值的位置,那么我们可以轻松地为任何给定的i查找合适的j。

这是一个C ++实现:

vector<int> solve(const vector<int> &A)
{
    int n = A.size();
    int sum = 0;
    int min = 0;
    vector<int> low_points;
    low_points.push_back(-1);
    // low_points[0] is the position where we first reached a sum of 0
    // which is just before the first index.
    vector<int> B(n,-1);
    for (int i=0; i!=n; ++i) {
        sum += A[i];
        if (sum<min) {
            min = sum;
            low_points.push_back(i);
            // low_points[-sum] will be the index where the sum was first
            // reached.
        }
        else if (sum>min) {
            // Go back to where the sum was one less than what it is now,
            // or go all the way back to the beginning if the sum is
            // positive.
            int index = sum<1 ? -(sum-1) : 0;
            int length = i-low_points[index];
            if (length>1) {
                B[i] = length;
            }
        }
    }
    return B;
}
2020-07-28