查找缺失的最小的正整数_数组中最小的缺失正整数

查找缺失的最小的正整数

问题: (Problem:)

Given an array of integers, find the first missing positive integer in linear time and constant space. In other words, find the lowest positive integer that does not exist in the array. The array can contain duplicates and negative numbers as well.

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

For example, the input [3, 4, -1, 1] should give 2. The input [1, 2, 0] should give 3.

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

You can modify the input array in-place.

您可以就地修改输入数组。

解: (Solution:)

This problem is interesting for several reasons:

这个问题很有趣,原因如下:

  1. It doesn’t fit in any of the standard-bucket algorithmic techniques, like hashing, graph traversal, etc.

    它不适合任何标准存储桶算法技术,例如散列,图遍历等。
  2. The simplest/inefficient solutions can be easily found and coded, but the strict efficiency conditions of the problem are harder to meet.

    最简单/效率最低的解决方案可以轻松找到并编码,但是很难满足该问题的严格效率条件。
  3. We need an “aha” moment to see the solution!

    我们需要一个“哈哈”的时刻来查看解决方案!

Let’s quickly sketch a simple solution using an unordered_set. Simply store every integer in an unordered_set, iterate from 1 to the length of the array and perform an O(1) set-lookup to find the smallest number.

让我们使用unordered_集合快速勾画一个简单的解决方案。 只需将每个整数存储在unordered_set ,从1迭代到数组的长度,然后执行O(1)设置查找以找到最小的数字。

Although this algorithm runs in linear time, it takes an extra linear space to store the set.

尽管此算法以线性时间运行,但是它需要额外的线性空间来存储集合。

There are two important insights for solving this problem with constant space:

使用恒定空间解决此问题有两个重要见解:

  1. For an array of size N, the solution is one of {1, 2, 3, ..., N+1}. So, for example, the smallest missing integer in an array of size 4, has to be one of {1, 2, 3, 4, 5}. (Sure enough, the solution to the example above, {3, 4, -1, 1} is 2). Why? This is because of a famous mathematical principle, called The Pigeon Hole Principle. Assume, if possible, that the smallest positive missing integer in the array of size N is greater than N+1. For this to happen, every integer from 1 to N+1 must be present in the array. However, the array only has a size of N, and cannot accommodate N+1 integers, contradicting our initial assumption. Hence, for an efficient algorithm, we can ignore all the elements of the array outside the interval [1, N+1].

    对于大小为N的数组,解为{1, 2, 3, ..., N+1} 。 因此,例如,大小为4的数组中最小的缺失整数必须为{1, 2, 3, 4, 5} 。 (当然,上述示例{3, 4, -1, 1}2 )。 为什么? 这是由于一种著名的数学原理,即“鸽子洞原理”。 如有可能,假设大小为N的数组中最小的正缺失整数大于N+1 。 为此,数组中必须存在从1N+1每个整数。 但是,该数组仅具有N的大小,不能容纳N+1整数,这与我们最初的假设相矛盾。 因此,对于有效的算法, 我们可以忽略间隔 [1, N+1] 之外的数组的所有元素

  2. The second insight is that we can use the original array itself as a hash-table/set to store whether a number is present!. We can do that by simply changing the sign of the original number!. The smallest missing integer can then be found by finding the first position in the array that stores a positive number, and returning its index.

    第二个见解是,我们可以使用原始数组本身作为哈希表/集来存储是否存在数字! 我们可以通过简单地更改原始数字的符号来做到这一点! 然后,可以通过找到数组中存储正数的第一个位置并返回其索引来找到最小的丢失整数。

Both of these insights will become clear by working out an example. Consider an array:

通过举例说明,这两种见解将变得清晰。 考虑一个数组:

A = {1, -2, 3, -4, 5, -6, 7}
  • The size of the array is 7. And hence the only possible solution must be in [1, 8]. We can ignore all the numbers in the array outside this range. For doing that, we can reshuffle the array so that all the numbers in [1, 8] come to the front, and the rest are sent to the back. Like this:

    数组的大小为7 。 因此,唯一可能的解决方案必须在[1, 8] 。 我们可以忽略该范围之外的数组中的所有数字。 为此,我们可以重新排列数组,使[1, 8]中的所有数字都位于最前面,其余的都发送到最后面。 像这样:

A = {1, 7, 3, 5, -4, -6, -2}
  • For the next iteration, assume that the array indices start with 1 instead of the usual 0. We iterate from the left of the array, for every number i, we flip the sign of ith index of the array to negative.

    对于下一次迭代,假定数组索引以1而不是通常的0开头。 我们从数组的左侧进行迭代,对于每个数字i ,我们将数组 ith 索引 的符号翻转 为负数。

  1. The first element of above array is 1. Flipping the sign of the 1st index in the array gives us {-1, 7, 3, 5, -4, -6, -2}.

    上面数组的第一个元素是1 。 翻转数组中第一个索引的符号将得到{-1, 7, 3, 5, -4, -6, -2}

  2. The second element of the array is 7. The sign of the 7th element is already negative, so we leave the array in-tact.

    数组的第二个元素是7 。 第7个元素的符号已经为负,因此我们将数组保持完整。

  3. The third element of the array is 3. Flipping the sign of 3rd index of the array gives us {-1, 7, -3, 5, -4, -6, -2}.

    数组的第三个元素是3 。 翻转数组的第三个索引的符号,我们得到{-1, 7, -3, 5, -4, -6, -2}

The end of this iteration gives us the following array:

迭代结束后,我们得到了以下数组:

A = {-1, 7, -3, -5, -4, -6, -2}

What’s the first positive number is the array? 7. What’s its index in the array? 2 (Remember one-based indexing). As a result, the smallest missing positive integer in the array is (drumroll) 2.

数组的第一个正数是多少? 7 。 它在数组中的索引是什么? 2 (记住基于一的索引)。 结果,数组中最小的缺失正整数为(drumroll) 2

实现方式: (Implementation:)

The implementation is simple: we just need to be careful about array indexing, bound checks etc.

实现很简单:我们只需要注意数组索引,绑定检查等。

测试: (Testing:)

There are quite a few corner cases for this problem:

这个问题有很多特殊情况:

  1. Empty array

    空数组
  2. Single element array {1}

    单元素数组{1}

  3. Single element array {1}

    单元素数组{1}

  4. Array of size n with all elements [1, n] present

    大小为n数组, n包含所有元素[1, n]

  5. Array of size n with all elements [0, n-1] present.

    大小为n数组, n包含所有元素[0, n-1]

Let’s test them all

让我们全部测试

Let’s try some of the examples from the problem statement

让我们尝试问题陈述中的一些例子

Finally, let’s try a complicated example.

最后,让我们尝试一个复杂的示例。

  1. Create an array from [1, n] for a random n.

    [1, n]创建一个数组[1, n]用于随机n

  2. Add some elements outside the range [1, n], and test that the smallest missing number is n+1.

    添加[1, n]范围之外的一些元素,并测试最小的缺失数为n+1

Originally published at https://cppcodingzen.com on September 1, 2020.

最初于 2020年9月1日 发布在 https://cppcodingzen.com 上。

翻译自: https://medium.com/@cppcodingzen/smallest-missing-positive-integer-in-an-array-b6f197e78a16

查找缺失的最小的正整数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值