找到特定缺失的数组元素:O(n + k)复杂度

时间:2017-05-30 07:44:25

标签: arrays algorithm big-o

我必须创建一个算法,该算法返回大小为 n 的数组中最大的缺失元素,其范围为值1- k

示例:如果数组包含1,1,3,1,3则k = 3,n = 5,返回值应为2.

如果不考虑时间复杂性,这是相对简单的;简单地遍历数组搜索k-1,k-2,... 2,并且第一次找不到值时,返回该值(如果不存在这样的值,则返回-1)。但是,这将是循环内的循环,导致O(n * k)复杂度。

我特意要求在我的结果中实现O(n + k),虽然我是算法设计的新手,但我相信这意味着我的算法不被允许包含任何嵌套循环。我所学的数组排序方法都没有线性最坏情况时间,所以我不能使用它们,我也看不到任何其他方法来保持n和k在所有段中分离。

我已经被困在这个概念上好几个小时了。我不一定要找到一个完整的答案,但是如果有人能指出我正确的方向,或者甚至解释我应该如何在这样的问题中接近O(n + k)复杂度,我就会非常感激。

3 个答案:

答案 0 :(得分:3)

带注释的C#示例代码:

int k = 3;

int[] data = new int[] {1, 1, 3, 1, 3};

// Step 1: collecting items presented
// O(n): we have to scan "data" array == O(n), adding item - n * O(1) == O(n)
// O(n) + n * O(1) == O(n) + O(n) == O(n) for the step 1

HashSet<int> present = new HashSet<int>(data);

// Step 2: scan 1..k items and find items missing:
// O(k) - 1..k scan + k * O(1) - checking each item
// O(k) + k * O(1) == O(k) + O(k) = O(k) for the step 2  

var missing = Enumerable
  .Range(1, k)                             // O(k) - scan     
  .Where(item => !present.Contains(item))  // k * O(1) == O(k) 
  .ToList(); // materialize 

// Test
Console.Write(string.Join(" ", missing));

最后,我们有第1步,然后是第2步:

O(n) + O(k) = O(n + k)  

编辑第2步 Linq lambda ,但旧的 for loop

for (int i = 1; i <= k; ++i) // O(k) - scan
  if (!present.Contains(i))  // O(1) - check
    Console.WriteLine(i);

答案 1 :(得分:2)

你可以使用另一个数组来存储事件而不使用hashset,尽管它会浪费一些内存,

public int maxMissingElement(final int arr[], final int max) {
boolean[] holder = new boolean[max + 1];

for (int i = 0; i < arr.length; i++) {
  holder[arr[i]]=true;
}

for (int i = max - 1; i >= 0; i--) {
  if (!holder[i]) {
    return i;
  }
}
return -1;
}

时间复杂度:O(n + k)

空间复杂度:O(k)

答案 2 :(得分:1)

我想到的第一件事就是保留一个大小为k的哈希集。哈希集具有以线性k时间创建的属性,查找数据的时间为O(1)

这意味着您可以为每个k值创建一个带有标志的哈希集(或字典)。因此,对于k = 3,您需要设置(0 -> false, 1 -> false, 2 -> false, 3 -> false)

然后,您可以简单地在线性n时间内遍历数据数组(大小为n),并且对于每个值,只需将哈希集中的相应记录设置为true即可。

在此过程之后,您最终得到的哈希集仅将记录设置为true,仅用于数据集中存在的值。

最后,只需遍历哈希集一次,并保留一个名为result的对象。每次找到false的值(即数据数组中不存在)时,都会将其与result进行比较。如果该值大于result,则将result设置为该值。

在哈希集循环结束时,result中的值将是数据集中最大的缺失值。

它是O(k + n)吗?

  • 我们创建了哈希集= O(k)
  • 我们遍历数据集,每次检查哈希集= O(n)* O(1)
  • 我们走过哈希集,比较和更新变量= O(k)* O(1)

我们将这些时间复杂性加起来如下:

 O(k) + O(n)O(1) + O(k)*O(1)
 = 2 * O(k) + O(n) = O(k) + O(n)
 = O(k + n).

注意

保持哈希设置听起来很实用,但不是很优雅。我确信在没有哈希集的情况下有一种方法可以做到这一点,但它符合问题的限制。