我必须创建一个算法,该算法返回大小为 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)复杂度,我就会非常感激。
答案 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)
= 2 * O(k) + O(n) = O(k) + O(n)
= O(k + n).
保持哈希设置听起来很实用,但不是很优雅。我确信在没有哈希集的情况下有一种方法可以做到这一点,但它符合问题的限制。