返回

算法详解:寻找缺失的第一个正数

前端

算法概述

给定一个未排序的整数数组,寻找其中没有出现的最小的正整数。例如,对于数组 [1, 2, 0, -5, 3], 缺失的第一个正整数是 4,而对于数组 [0, 1, 2, 3], 则为 4

要解决这个问题,我们提出了一种有效且高效的算法。该算法遵循以下步骤:

  1. 首先,我们将数组中的所有正整数移动到数组的前部。
  2. 然后,对数组中正整数的位置进行调整,使其满足每个数字的索引等于该数字减一。
  3. 最后,遍历数组,找到第一个缺失的正整数,即第一个未被占用的索引加一。

算法实现

1. 将正整数移动到数组的前部

我们将使用一个双指针法来实现这一步。我们将两个指针都初始化为 0。左指针指向数组的起始位置,而右指针指向数组的末尾。然后,我们循环检查右指针指向的元素。如果该元素为正整数,我们将该元素与左指针指向的元素交换,并同时将左指针和右指针都右移一位。如果该元素为负整数或零,则我们仅右移右指针。

2. 调整正整数的位置

在第一步中,我们将所有正整数都移动到了数组的前部。现在,我们需要将这些正整数的位置调整正确。我们可以通过以下步骤来实现:

  1. 我们遍历数组中正整数的位置。
  2. 对于每个正整数,我们计算其正确位置的索引。该索引等于该正整数减一。
  3. 如果该正整数不在其正确位置,我们将该正整数与该位置处的元素交换。

3. 查找缺失的第一个正整数

在第二步中,我们将所有正整数都调整到了正确的位置。现在,我们需要找到第一个缺失的正整数。我们可以通过以下步骤来实现:

  1. 我们遍历数组中正整数的位置。
  2. 对于每个正整数,我们检查该正整数的索引是否等于该正整数减一。
  3. 如果该正整数的索引不等于该正整数减一,则说明该正整数的索引加一就是第一个缺失的正整数。

算法分析

时间复杂度

该算法的时间复杂度为 O(n),其中 n 是数组的长度。我们在步骤 1 和步骤 2 中都使用了双指针法,该方法的平均时间复杂度为 O(n)。步骤 3 中的遍历操作也需要 O(n) 的时间。

空间复杂度

该算法只需要常数级别的额外空间。我们在步骤 1 和步骤 2 中使用了两个指针,这需要两个额外的变量。在步骤 3 中,我们也需要一个额外的变量来存储第一个缺失的正整数。因此,该算法的空间复杂度为 O(1)。

边界情况

如果数组中没有正整数,则第一个缺失的正整数为 1。如果数组中没有负整数或零,则该算法将始终返回 1。

示例

对于数组 [1, 2, 0, -5, 3], 该算法将返回 4。
对于数组 [0, 1, 2, 3], 该算法将返回 4。
对于数组 [-1, -2, -3], 该算法将返回 1。
对于数组 [], 该算法将返回 1。

结论

本文详细解析了算法题“查找缺失的第一个正数”,提供了一种时间复杂度为 O(n) 且仅使用常数级别额外空间的解决方案。我们还讨论了该算法的实现细节和一些边界情况的处理。希望本文对有志于算法学习的读者有所帮助。