给定一个整数数组,找到线性时间和常量空间中第一个缺失的正整数。换句话说,找到数组中不存在的最小正整数。该数组也可以包含重复数字和负数。
例如,输入[3,4,-1,1]应该给出2.输入[1,2,0]应该给出3。
我做了这个,但无法通过它,然后在谷歌搜索它并得到极客的极客的答案,但无法理解。任何人都可以使用简单的概念为此提供逻辑吗?我刚刚开始竞争性编程。
答案 0 :(得分:1)
如果位图(位掩码的扩展名)是可接受的,那么我们可以使用每正正整数1位然后滚动数组。将位图初始化为所有位为0.当我们滚动数组时,我们忽略负数并在遇到n时将第n位置ON。当我们找到例如13时,我们将第13位变为1.(同样,数字1将第一位变为1)然后我们滚动位掩码并检查第一个零。完成。
然而,这可能根本不被视为常数复杂,因为当max positive int为MAXINT时,我们需要位图为MAXINT位大。太糟糕了。但从理论上讲,这是正确的。 O(2 * N)= O(N)
所以我们必须在数组中存储一些信息,否则一次性就无法在O(N)中解决这个问题。
另一种解决方案包括使用整数映射数组索引并使用符号存储信息。例如,如果数组大小为L,那么缺少的int将小于或等于L + 1(如果数组满,则为L + 1,如[1,2,3,4],除非此情况计为没有元素丢失)。 感谢Jarod对此的暗示。
考虑到O(3N)仍然是O(N),怎么样:
步骤1:滚动数组并交换负数和零,将它们移动到开头。把所有非正面的东西,换成这种方式,转换为1.真正的正面将从索引j开始。
第2步:整个数组现在都是正数,但真正的数据是从j到数组的末尾。使用真实数据滚动子阵列,当您找到编号H时,将索引编入整个数组的Hth索引编号。如果H大于数组大小,请跳过它。当你找到例如2时,转动arr [1](第二个元素)为负。
步骤3:再次滚动数组,检查第一个正数。基于索引,您知道第一个缺少的正整数是什么。
答案 1 :(得分:1)
找到解决方案的一种方法是重新排列数组,然后找到第一个 号码错位:
int find_missing(std::vector<int>& v)
{
for (std::size_t i = 0; i != v.size(); ++i) {
std::size_t e = i;
while (0 < v[e] // Correct range
&& std::size_t(v[e]) <= v.size() // Correct range
&& std::size_t(v[e]) != e + 1 // Correct place
&& v[e] != v[v[e] - 1] // Duplicate
) {
std::swap(v[e], v[v[e] - 1]);
}
}
// Now the array look like
// {1, 2, 3, x, 5, 6, x}
// Find first misplaced number
for (std::size_t i = 0; i != v.size(); ++i) {
if (std::size_t(v[i]) != i + 1) {
return i + 1;
}
}
// All are correctly placed:
return v.size();
}