我正在尝试编写一个算法,该算法将返回True/False
排序数组中仅包含正整数的连续序列,可以总计为N
。
例如:
Array = { 1, 2, 3, 4 };
6 is good! 1 + 2 + 3 = 6
8 is not good! 1 + 3 + 4 = 8, but it's not contiguous, since we skipped the 2.
这就是我试图做的事情:
int[] arr = ...;
int headIndex = 1, tailIndex = 0, sum = arr[0];
while (sum != n)
{
if (sum < n)
{
sum += arr[headIndex++];
}
if (sum > n)
{
sum -= arr[tailIndex++];
}
}
return sum == n;
显然上面的内容不起作用(在某些情况下,它可能会陷入无限循环)。有什么建议吗?
我之前没有提到的一件事,非常重要 - 算法的复杂性必须尽可能低。
答案 0 :(得分:8)
这只是一幅草图:
k
n1 + ... + nk <= target
的最大sum = n1 + ... + nk
,设置sum == target
。如果数组总和小于目标,则返回false。S
,我们就完成了。如果不是,那么总和为target
的任何子数组S.length < k
将具有sum -= n1
,并且将从大于第一个的元素开始。因此,我们从总和中取出第一个:leftEnd++
,k
。现在我们可以回到第1步,但不需要从头开始计算{{1}}。由于左端最多移动N次,右端移动最多N次,因此该算法具有时间复杂度O(N)和恒定空间要求。
答案 1 :(得分:0)
简单地:
for i = 1 to n - 1:
j = 0
while (j < i):
sm = 0
for k = j to i:
sm = sm + array[k]
if sm == N:
return True
j = j + 1
return False
这适用于 O(n ^ 3)时间。
答案 2 :(得分:0)
var i = 0;
while(i != arr.Length)
{
var remembre = i;
var tmp = 0;
for(; tmp < N && i < arr.Length; ++i)
tmp += arr[i];
if(N == tmp)
return true;
i = remembre + 1;
}
return false;
我相信这应该有用。
答案 3 :(得分:0)
这是代码中的解决方案。它受到了@Ziyao Wei的草图的极大影响,它简化了我的原始方法(特别是,没有必要回溯并添加小数字,只是按照我的想法将它们取下来。)
public static bool HasConsecutiveSum(IList<int> list, int requiredSum)
{
int start = 0;
int sum = 0;
for (int end = 0; end < list.Count; end++)
{
sum += list[end];
while (sum > requiredSum)
{
sum -= list[start++];
if (start > end)
{
return false;
}
}
if (sum == requiredSum)
{
return true;
}
}
return false;
}
答案 4 :(得分:0)
我认为最优化的算法适用于在列表上移动的窗口。窗口的值(WV)是窗口内元素的总和。如果WV小于N,则移动头部并将适合窗口的新值添加到WV,如果该值大于N,则将尾部向上移动一个并从WV中减去窗口下降的值。当WV等于N,或者尾部移动到头部之外,或者头部位于列表的末尾,并且WV仍然为低时,算法停止。
这将以线性时间运行:列表中的每个元素都被添加一次,最多减去一次。
写下一些代码来说明这个想法(python一样),但没有经过测试
WV = list[0]
L = len(list)
tail = 0
head = 0
while WV != N
if WV < N
head += 1
if head < L
WV += list[head]
else
return false // beyond end of list
elif WV > N
if tail < head
WV -= list[tail]
tail += 1
else
return false // single element bigger then N, and list is sorted
return true