问题:给定排序的数组A,找出A中元素的所有可能差异。
我的解决方案:
for (int i=0; i<n-1; ++i) {
for (int j=i+1; j<n; ++j) {
System.out.println(Math.abs(ai-aj));
}
}
当然,它是O(n ^ 2),但我根本不算数。我在网上看了一下,发现了这个:http://www.careercup.com/question?id=9111881。它说你不能做得更好,但在接受采访时我被告知你可以做O(n)。哪个是对的?
答案 0 :(得分:18)
首先想到的是你没有使用数组排序的事实。让我们假设它处于递增的顺序(减少可以类似地处理)。
我们也可以使用差异望远镜(i&gt; j)的事实:
a_i - a_j = (a_i - a_(i-1)) + (a_(i-1) - a_(i-2)) + ... + (a_(j+1) - a_j)
现在构建一个新序列,称之为s,它具有简单的差异,意思是(a_i - a_(i-1))
。这只需要传递一次(O(n)
),您也可以跳过重复,这意味着如果a_i
则跳过a_i = a_(i+1)
。
a_i-a_j
与i>j
的所有可能差异均为s_i + s_(i+1) + ... + s_(j+1)
。所以,如果你认为它已经找到它们,那么你可以在O(n)
时间内完成它。但是,要打印它们,可能需要n(n-1)/2
次呼叫,这绝对是O(n^2)
。
答案 1 :(得分:11)
例如,对于元素 {2 1 ,2 2 ,...,2 n } < / em>存在n⋅(n-1)/ 2 可能的差异,并且它们中没有两个是相等的。所以有 O(n 2 )的差异。
由于你必须枚举所有这些,你至少还需要 O(n 2 )时间。
答案 2 :(得分:1)
排序或未排序并不重要,如果你必须计算每个差异,那么就没有办法在n ^ 2之内做到这一点,
问题被问错了,或者你只做O(n)然后再打印42次N:D答案 3 :(得分:1)
如果面试官喜欢理论游戏,也许他正在考虑使用输入和结果表? 任何问题都有输入大小的限制,并且有一个已知的解决方案,可以通过表查找来解决。鉴于您首先创建并存储了该表,该表可能是 large 。
因此,如果数组大小有限,可以通过表查找解决问题,这可以在恒定时间内完成(给定一些假设)。当然,即使最大阵列大小 2 (假设32位整数),该表也不适合普通计算机的内存或磁盘。对于较大的阵列最大尺寸,您将进入“不适合已知宇宙”的大小。但是,从理论上讲,它可以做到。
(但实际上,我认为Jens Gustedt的评论更有可能。)
答案 4 :(得分:1)
是的,您肯定可以做到这一点。 要找出O(n)的差异,您将需要使用BitSet(C ++)或相应语言的任何类似数据结构。
初始化两个位,例如A和B 您可以执行以下操作: 对于通过数组的每次迭代: 1-在BitSet A中存储连续的差异 2左移B BitSet B中的3个存储的连续差异 四拍A = A或B
例如,我给出了代码- 这里N是数组的大小
for (int i=1;i<N;i++){
int diff = arr[i]-arr[i-1];
A[diff]=1;
B<<=diff;
B[diff]=1;
A=A | B;
}
A中的位为1将是差异。
答案 5 :(得分:0)
您可以通过假设数组内容在排序之前是随机整数来获得另一个反例。那么两个差异,Ai-Aj与Ak-Al,甚至是Ai-Aj与Aj-Ak相同的可能性太小,只有O(n)明显的差异Ai-Aj。
鉴于此,面试官的问题是解释允许O(n)解决方案的特殊情况。一种可能性是数组值都是0..n范围内的数字,因为在这种情况下,最大绝对差值仅为n。
我可以在O(n lg n)中执行此操作,但不能在O(n)中执行此操作。通过大小为n + 1的数组表示数组内容,其中元素i设置为1,其中数组中存在值i。然后使用FFT将数组与自身进行卷积 - 存在差异Ai-Aj = k,其中卷积的第k个元素为非零。
答案 6 :(得分:0)
首先需要对数组进行排序
让我们考虑一个排序数组 ar = {1,2,3,4}
所以我们在 O(n^2) 上做了什么
for(int i=0; i<n; i++)
for(int j=i+1; j<n; j++) sum+=abs(ar[i]-ar[j]);
如果我们在这里精心操作,它会看起来像下面
when i = 0 | sum = sum + {(2-1)+(3-1)+(4-1)}
when i = 1 | sum = sum + {(3-2)+(4-2)}
when i = 2 | sum = sum + {(4-3)}
如果我们都写了
sum = ( -1-1-1) + (2+ -2-2) + (3+3 -3) + (4+4+4 )
我们可以看到
索引 0 处的数字加 0 次总和并从总和中减去 3 次。
将索引 1 处的数字与总和相加 1 次,然后从总和中减去 2 次。
将索引 2 处的数字与总和相加 2 次,然后从总和中减去 1 次。
将索引 3 处的数字加到总和中 3 次,然后从总和中减去 0 次。
所以我们可以这么说,
the number at index i will be added to the sum for i time
and will be substracted from the sum for (n-i)-1 time
那么广义表达式为 每个元素将是
sum = sum + (i*a[i]) – ((n-i)-1)*a[i];