以下是编程任务。
您将获得一系列N个整数。任务是找到连续的整数序列的数量,使它们的和为零。
例如,如果序列是: 2,-2,6,-6,8 有3个这样的序列:
我已经有用PHP编写的以下程序,它读取STDIN
的输入(第一行包含后面的整数。)
<?php
$n = fgets(STDIN) * 1;
$seq = array();
for ($i = 0; $i < $n; $i++) {
$seq[] = fgets( STDIN ) * 1;
}
$count = 0;
for( $i = 0; $i < $n; $i++)
{
$number = 0;
for( $j = $i; $j < $n; $j++)
{
$number += $seq[$j];
if( $number == 0 )
$count++;
}
}
echo 'count: ' . $count . PHP_EOL;
输入示例
5
2
-2
6
-6
8
这适用于较小的序列,但其效率为O(n ^ 2)。
对于包含100.000个整数的序列,什么算法是合适的 - 可能是O(n)效率?
答案 0 :(得分:7)
假设您的数据存储在一个数组中,并让它为arr
。
创建一个数组sum
,例如:
sum[i] = arr[0] + arr[1] + ... + arr[i]
另外,在开头的一个条目为0(处理从开头开始并总和为零的子数组)
现在,很容易看出,对于i,j
和i<j
这两个索引sum[i]=sum[j]
,连续序列arr[i+1]+arr[i+2]+...+arr[j] = 0
。
通过创建此数组sum
,您只需要找到有多少重复项。这不能在O(n)
1 (这是element distinctness problem)中完成,但可以使用排序在O(nlogn)
中解决,然后迭代和计数,这仍然是非常快速的100,000个条目。
请注意,如果数组n
中的数字k
存在sum
个重复项,则会为这些重复项生成Choose(n,2) = n(n-1)/2
个连续子序列。
示例:强>
arr = [1,2,-2,5,6,-6,-5,8]
sum = [0,1,3,1,6,12,6,1,9]
sorted(sum) = [0,1,1,1,3,6,6,9,12]
有3个重复的1个和2个重复的6个,所以总共有:
Choose(3,2) + Choose(2,2) = 3*2/2 + 2/2 = 3+1 = 4
确实匹配4个子序列:
2,-2
2,-2,5,6,-6,-5
6,-6
5,6,-6,-5
(1)没有散列,然后你会衰减到O(n ^ 2)最坏的情况,但会从O(n)
平均情况中受益,代价为O(n)
额外空间。
答案 1 :(得分:0)
由于我无法回复评论,这是对amit答案的回复。 也许我有些不对劲,但在将您的方法应用于原始测试用例时,我们无法得到正确的答案:
input = [2, -2, 6, -6, 8]
sum = [2, 0, 6, 0, 8]
sorted(sum) = [0, 0, 2, 6, 8]
由于数字0有两个重复,这给我们(2 * 1)/ 2 = 1,这是不正确的(正确的答案是3)。 我错过了什么?感谢