返回
找出数组中缺失的第一个正数:LeetCode 41
前端
2023-12-23 17:19:34
导言
在计算机科学中,查找数组中缺失的第一个正数是一个经典问题。这个问题有多种解决方法,每种方法都有其独特的优点和缺点。本文将介绍 LeetCode 41 题的两种高效解决方案,并深入探讨每种方法的复杂度和实现细节。
LeetCode 41 题
给定一个未排序的整数数组,找出其中没有出现的最小的正整数。
解决方案 1:哈希表法
思想: 哈希表法是一种使用哈希表来存储数组中出现的数字的方法。一旦数组中的所有数字都被添加到哈希表中,我们可以遍历正整数,直到找到一个不在哈希表中的数字。这个数字就是数组中缺失的第一个正数。
算法步骤:
- 创建一个哈希表,将数组中所有数字作为键添加到其中。
- 从正整数 1 开始遍历,直到找到一个不在哈希表中的数字。
- 将找到的数字返回为缺失的第一个正数。
代码实现:
def first_missing_positive_hash(nums):
hashset = set(nums)
i = 1
while i in hashset:
i += 1
return i
复杂度分析:
- 时间复杂度:O(n),其中 n 是数组 nums 的长度。遍历数组需要 O(n) 时间,遍历正整数也需要 O(n) 时间。
- 空间复杂度:O(n),因为哈希表存储了数组中的所有数字。
解决方案 2:置换法
思想: 置换法是一种利用数组中元素的正负符号来标识缺失数字的方法。我们遍历数组,将正数移动到数组的开头,将负数移动到数组的末尾。然后,我们遍历数组的正数部分,将每个数字交换到其索引 + 1 的位置。最后,我们遍历数组的正数部分,找到第一个不在正确位置的数字。这个数字就是数组中缺失的第一个正数。
算法步骤:
- 遍历数组,将正数移动到数组的开头,将负数移动到数组的末尾。
- 遍历数组的正数部分,将每个数字交换到其索引 + 1 的位置。
- 遍历数组的正数部分,找到第一个不在正确位置的数字。
- 将找到的数字返回为缺失的第一个正数。
代码实现:
def first_missing_positive_swap(nums):
n = len(nums)
i = 0
j = n - 1
# 将正数移动到数组的开头,负数移动到数组的末尾
while i <= j:
if nums[i] > 0:
nums[i], nums[j] = nums[j], nums[i]
j -= 1
else:
i += 1
# 将每个正数交换到其索引 + 1 的位置
for i in range(n):
if nums[i] <= 0 or nums[i] > n:
nums[i] = n + 1
else:
index = nums[i] - 1
while nums[index] > 0:
temp = nums[index]
nums[index] = -1
index = temp - 1
# 找到第一个不在正确位置的数字
for i in range(n):
if nums[i] > 0:
return i + 1
return n + 1
复杂度分析:
- 时间复杂度:O(n),其中 n 是数组 nums 的长度。遍历数组和交换数字都需要 O(n) 时间。
- 空间复杂度:O(1),因为我们没有使用额外的空间来存储中间结果。
总结
LeetCode 41 题的两种解决方案——哈希表法和置换法——都有其优点和缺点。哈希表法更简单、更容易理解,但空间复杂度更高。置换法空间复杂度更低,但算法步骤更复杂。根据具体情况,选择最适合的解决方案。
练习
- 尝试使用两种方法解决 LeetCode 41 题。
- 探索哈希表法和置换法在处理其他类型问题时的应用。
- 设计自己的算法来解决 LeetCode 41 题。
补充阅读