繁体   English   中英

在数组中找到缺少的数字,时间复杂度O(N),空间复杂度O(1)

[英]Find missing numbers in array, time complexity O(N), space complexity O(1)

给出一个n个唯一整数0 <= x_i <2 * n的数组。 打印此数组中不存在的所有整数0 <= x <2 * n。

例:

find_missing([0])= [1]

find_missing([0,2,4])= [1,3,5]#因为所有数字都是[0,1,2,3,4,5]

find_missing([])= []

find_missing([0,1,4,5])= [2,3,6,7]#因为所有数字都是[0,1,2,3,4,5,6,7]

怪癖是关于要求:

时间复杂度O(n) - 但是应该有一些与输入大小无关的固定常数C,这样数组的每个元素都被写入/读取<C次,所以对数组进行基数排序是不行的。

空间复杂度O(1) - 你可以修改初始数组,BUT sorted(ini​​tial_array)必须等于sort(array_after_executing_program)并且你不能在这个数组中存储范围[0,2n]之外的整数(想象它是uint32_t的数组) )。

我看到了很多复杂的解决方案,但后来我发现了这个:

public void printNotInArr(int[] arr) {
    if(arr == null)
        return null;

    int len = arr.length;
    int max = 2 * len;

    for(int i = 0; i < len; i++) {
        System.out.println(max - arr[i] - 1);
    }
}

我相信这是最好的解决方案,但我不确定。 我想知道为什么那不起作用。

正如@ LasseV.Karlsen指出的那样,[0,3]是一个简单的反例,展示了该解决方案不起作用的方式。 然而,这是一个非常简单的解决方案(在Python中):

def show_missing(l):
  n = len(l)

  # put numbers less than n into the proper slot
  for i in range(0,n):
    while l[i]<n and l[i]!=i:
      j = l[i]
      l[i] = l[j]
      l[j] = j
  for i in range(0,n):
    if l[i]!=i:
      print('Missing %s'%i)

  # put numbers greater than n into the proper slot
  for i in range(0,n):
    while l[i]>=n and l[i]!=i+n:
      j = l[i]
      l[i] = l[j-n]
      l[j-n] = j
  for i in range(0,n):
    if l[i]!=i+n:
      print('Missing %s'%(i+n))

这个想法很简单。 我们首先重新排列元素,以便每个小于n的值j存储在索引j处。 然后我们可以通过数组并轻松挑选出缺少的n以下的数组。

然后,我们重新排列元素,使得大于或等于n的每个值j都存储在索引jn处。 同样,我们可以通过数组并轻松挑选出大于或等于n的数组。

由于仅使用几个局部变量,因此满足O(1)空间复杂度。

由于嵌套循环,O(n)时间复杂度有点难以看出,但是要表明我们从不交换n个元素并不太难,因为一个新元素被放入其适当的位置交换。

由于我们只交换了数组的元素,因此也满足了所有原始元素仍在数组中的要求。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM