我需要打印一个int数组的任何两个元素之间的最小差异。
数组A
的每个元素小于其长度。
1 <= A[i] <= A.length;
我已经在Java中尝试了以下指定方法- 但是,在给定数组大小〜10 ^ 5的情况下,要花1秒钟以上的时间才能找到结果。
我认为这可能是一种幼稚的方法。有什么办法可以进一步优化它?
可以在O(n)
时间复杂度内完成吗?
static int findResult(int[] arr)
{
int max = Integer.MAX_VALUE;
HashSet<Integer> hs = new HashSet<Integer>();
for(int obj : arr)
{
hs.add(obj);
}
if(hs.size()==1 )
{
return 0; // if all elements are same
}
for(int i=0; i<arr.length; i++)
{
for(int j=i+1; j<arr.length; j++)
{
int value = Math.abs(a[i]-a[j]);
if(value<max)
{
max = value;
}
}
}
return max; // returns the smallest positive difference
}
答案 0 :(得分:4)
因为每个 x i 都认为1≤x i ≤n,所以,由于 pigeonhole原理,所有值要么精确地存在一次,要么重复存在两次或多次。
在前一种情况下,差异为1
(对于大于1个元素的数组),在后一种情况下,结果为0
,因为那时有两个项完全相等
因此,我们可以遍历数组并跟踪数字。如果一个数字已经存在一次,则返回0
,否则,返回1
,例如:
// only if it holds that for all i, 1 <= arr[i] <= arr.length
static int findResult(int[] arr) {
bool[] found = new bool[arr.length]
for(int i = 0; i < arr.length; i++) {
if(found[arr[i]-1]) {
return 0;
} else {
found[arr[i]-1] = true;
}
}
return 1;
}
对于满足 n 个元素的条件的随机数组,在 n!/ n n 的情况下,它将返回{ {1}},在其他情况下,它将返回1
,因此随机输入的平均值为 n!/ n n 。随着 n 越来越大,几乎没有“碰撞”的可能性越来越小,因此,随着@YvesDaoust says的出现,0
的近似值非常可能。
如果我们删除约束,我们可以首先对数组进行排序,在这种情况下,我们对连续的元素进行迭代:
0
答案 1 :(得分:1)
我假设A
是整数,否则条件1 <= A[i] <= A.len
不相关。
然后使用直方图提供一个O(n)
解决方案。
声明一个大小为A.length
的计数器数组;
计算A
元素的多重性;
扫描此直方图以找到最近的非空垃圾箱。
请注意,此解决方案假定仅考虑非零差异。如果零差计算在内,那么威廉的答案会更好。
答案 2 :(得分:0)
(添加到以上答案中)
如果需要使用O(1)多余的空间来执行此操作,则可以对输入序列A使用以下技巧:
for a in A[1...n]: // a is an element in A; A is 1-indexed; 1 <= a <= n
if M < A[a % M]:
return 0
A[a % M] += M
return 1
这里M(> n)使得M + n不会溢出。可以轻松地修改技巧,改为使用小于-n的M。
注意事项: