找到第一个缺失的正整数

时间:2018-05-31 21:52:10

标签: arrays

给定一个整数数组,找到线性时间和常量空间中第一个缺失的正整数。换句话说,找到数组中不存在的最小正整数。该数组也可以包含重复数字和负数。

例如,输入[3,4,-1,1]应该给出2.输入[1,2,0]应该给出3。

我做了这个,但无法通过它,然后在谷歌搜索它并得到极客的极客的答案,但无法理解。任何人都可以使用简单的概念为此提供逻辑吗?我刚刚开始竞争性编程。

2 个答案:

答案 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();
}

Demo