算法 - 查找数组的起始索引,使元素之和保持> = 0

时间:2016-10-05 11:18:15

标签: algorithm

我被告知这可以在O(n)中完成 - 时间和O(n)用于内存使用。

作为输入,我会查看一个intigers列表(数量为n - 从一开始就可用)。

任务是找到最低的索引(从左侧开始),使我能够通过数组(从起始索引到起始元素后面的索引做一个圆圈),这样变量总和 - 那个总结路上所有元素永远不会低于0。

*此数组中的所有元素总和为0。

例如: 1,-1,-3,3,4,-4

  1. 1 - 1 - 3 = -2< 0不是那个
  2. -1< 0
  3. -3< 0
  4. 3 + 4 - 4 + 1 - 1 - 3 = 0
  5. 是好的因为7> 0,3> 0,4> 0,3> 0,0 = 0:)

    我现在这样做的方式是我进入一个for循环n次, 我有两个for循环: 一个用于i->结束索引,另一个用于0-> i-1索引。

    这有效,但速度太慢,任何想法都值得赞赏。 (所有基于语言的程序性能改进都不够)

2 个答案:

答案 0 :(得分:3)

来自https://www.quora.com/Does-there-always-exist-a-rotation-of-a-circular-array-such-that-all-prefix-sums-for-that-rotation-are-non-negative-Given-that-sum-of-all-its-elements-is-non-negative

  

令序列为(1),a(2),...,a(N)。定义s_a(i)=   一(1)+ A(2)+ ... + A(I)。给出s_a(N)≥0(假设)。设j为   最大的索引,使得如果存在这样的j,则s_a(j)<0。显然,j   &LT; N.考虑序列a(j + 1),a(j + 2),...,a(N)。很容易看到   这个序列的所有前缀和都是≥0。如果   a(j + 1)+ a(j + 2)+ ... + a(k)小于0,s_a(k)小于   也是一个矛盾。

     

现在生成一个新序列{bi} =   第(j + 1),第(j + 2),...,A(N),一(1),(2),...,第(j)。很容易看到   这个新序列的前缀总和(称为它(i))没有达到   前N-j个元素的值小于零。此外,自从   保(N-j)≥0,如果s_a(i)是非负的,则(i + N-j)也是如此。

     

继续重复最右边的部分   具有负前缀和的位置并将其带到开头   的序列。在每一步,我们的起始范围   保证前缀总和将是非负的不断增加。但   这个数字以N为界,该序列的长度。这意味着   经过一些步骤后,将没有负前缀和   序列。因此,我们获得了原始序列的旋转   所有前缀加上非负数。

这是我的想法的简单O(n)实现。

int best_index(std::vector<int> & a){
    int n = A.size();

    long long array_sum=0;
    long long sum=0;
    int last_index=-1;
    for (int i = 0; i < n; ++i)
    {
        array_sum+=a[i];
        if (sum<0)
        {
            sum=0;
            if (a[i]>=0)
            {
                last_index=i;
            }
        }
        sum+=a[i];
    }

    if (array_sum<0)
    {
        return -1;
    }
    return last_index;
}

复杂性:O(n)

答案 1 :(得分:3)

我们首先累积元素的总和:

elements = [1, -1, -3, 3, 4, -4]
sums =     [1,  0, -3, 0, 4,  0]

(如果最后一个值为负,则没有解决方案)

因此,如果我们从索引0开始,我们就会得到这个序列。如果我们从索引1开始,所有数字将减少一个(并且围绕旋转,但我们并不关心它)。如果我们从索引2开始,那么数字就不会有所不同。我们可以看到,通过选择起始点,我们可以通过跳过的数字的值来上下移动整个序列。

我们的目标是将整个序列提升到足够高,以使任何值都不会变为负值。为此,我们必须在最小值之后立即开始 - 或者,如果有多个,则在第一个最小值之后开始。

我们可以在O(n)

中轻松找到
startingIndex (elements):
    sums = []
    sum = 0
    for (i = 0; i < elements.length; i++)
        sums[i] = sum
        sum += elements[i]
    if (sum < 0)
        throw "invalid input"
    min = 0
    index = 0
    for (i = 0; i < elements.length; i++)
        if (sums[i] < min)
            min = sums[i]
            index = i
    return index