我被告知这可以在O(n)中完成 - 时间和O(n)用于内存使用。
作为输入,我会查看一个intigers列表(数量为n - 从一开始就可用)。
任务是找到最低的索引(从左侧开始),使我能够通过数组(从起始索引到起始元素后面的索引做一个圆圈),这样变量总和 - 那个总结路上所有元素永远不会低于0。
*此数组中的所有元素总和为0。
例如: 1,-1,-3,3,4,-4
是好的因为7> 0,3> 0,4> 0,3> 0,0 = 0:)
我现在这样做的方式是我进入一个for循环n次, 我有两个for循环: 一个用于i->结束索引,另一个用于0-> i-1索引。
这有效,但速度太慢,任何想法都值得赞赏。 (所有基于语言的程序性能改进都不够)
答案 0 :(得分:3)
令序列为(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