【问题标题】:Longest positive subarray最长正子阵
【发布时间】:2018-01-16 20:54:20
【问题描述】:

数组 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) 的解决方案。

【问题讨论】:

  • 我假设您想要算法,而不是 C++ 中的实现?
  • @Phil Moesch 是的……你能说得更具体点吗?
  • @Vaughn Cato 更新
  • 子序列是否需要连续?
  • @PhamTrung en.wikipedia.org/wiki/Subsequence 根据定义不需要是连续的。看起来这不是 OP 的意思,应该有人编辑他的帖子以避免混淆。

标签: arrays algorithm


【解决方案1】:

诀窍是要意识到我们只需要找到最小的 j 使得(A[0] + ... + A[j-1]) == (A[0] + ... + A[i]) - 1A[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;
}

【讨论】:

    【解决方案2】:

    您可以考虑 +1/-1 的总和,就像我的图表一样。我们从 0 开始(没关系)。

    所以:在考虑任何点时,您希望得到在左侧另一点最远在它下方

    1 构造并保持总和

    需要 n 次迭代:O(n)

    2 构造一个表值=>点,迭代每一个点,并保持最左边:

    你得到:0 => a,1 => b(不是 d),2 => c(不是 e,i,k),3 => f(不是 h),4 => g(不是 m) , 5 => n, 6 => o

    需要 n 次迭代:O(n)

    每个级别 3 个(比如 0、1、2、3、...)=> 你保持最远的点,它在它下面:

    0 级 => 一个

    1 级 => 一个

    等等。 => 它永远是一个。

    假设图形从 g 点开始:

    4 => 克

    3 => h

    2 => 我

    5 => 克

    6 => g

    那么:如果一个点刚刚超过 3(那么 4:作为 m)=> 它将是 h

    它还需要 n 个最大操作(精确的图形高度)。

    4 迭代每个点:你的 B[i]。

    在每一点上,比如说 h : sum = 3,你在它下面最远(操作表 3):在我的模式中它总是 a = 0;

    假设图形从 g 点开始:

    积分

    g, h, i, k => 没有

    j => 我

    l => 我

    m => h

    n => g

    您可以在同一迭代中组合一些操作。

    【讨论】:

      猜你喜欢
      • 2017-01-26
      • 1970-01-01
      • 2021-04-28
      • 1970-01-01
      • 2017-11-29
      • 2016-05-04
      • 2021-09-01
      • 2013-04-13
      • 1970-01-01
      相关资源
      最近更新 更多