有什么方法可以使用单个循环比较数组中的每个元素吗?

Is there any way to compare each element in an array using a single loop?

我需要打印 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
    }

1≤xi≤n: O(n)

因为对于每个 xi 它认为 1≤xi≤n,它认为,由于pigeonhole principle,所有值都恰好存在once,或者一个值存在两次或更多次

在前一种情况下,差异是1(对于大于1个元素的数组),在后一种情况下,结果是0,自此有两项是完全相等。

因此我们可以遍历数组并跟踪数字。如果一个数已经存在一次,我们return0,否则,我们return1,如:

// 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!/nn 的情况下,它会 return 1,而在其他情况下,它会 return 0,所以随机输入的平均值是 n!/nn。随着 n 变大,没有 "collisions" 的可能性很小,因此,作为 0 的近似值很可能.

没有1≤xi≤n: O(n log n)

如果我们放弃约束,我们可以先对数组进行排序,在这种情况下,我们迭代连续的元素:

static int findResult(int[] arr) {
    Arrays.sort(arr);
    int dmin = arr[1] - arr[0];
    for(int i = 2; i < arr.length; i++) {
        int d = arr[i] - arr[i-1];
        if(d < dmin) {
            if(d == 0) {
                return 0;
            }
            dmin = d;
        }
    }
    return dmin;
}

我假设 A 是整数,否则条件 1 <= A[i] <= A.len 没有相关性。

然后有一个O(n)使用直方图的解决方案。

  1. 声明一个大小为 A.length 的计数器数组;

  2. 计算A的元素的重数;

  3. 扫描此直方图以找到最接近的非空 bin。


请注意,此解决方案假定仅考虑非零差异。如果零差异很重要,那么 Willem 的答案更好。

(添加到上述答案中)

如果你需要用额外的 O(1) 来做到这一点 space,你可以在输入序列 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。

注意事项:

  1. 需要随机(即 O(1))访问 A 的元素。
  2. 缓存不友好。