作者介绍:10年大厂数据\经营分析经验,现任大厂数据部门负责人。
会一些的技术:数据分析、算法、SQL、大数据相关、python
欢迎加入社区:码上找工作
作者专栏每日更新:
LeetCode解锁1000题: 打怪升级之旅
python数据分析可视化:企业实战案例
备注说明:方便大家阅读,统一使用python,带必要注释,公众号 数据分析螺丝钉 一起打怪升级
LeetCode题目41“缺失的第一个正数”要求在未排序的整数数组中找出最小的未出现的正整数。本文将详细介绍三种解决这一问题的方法,包括解题思路、详细的代码实现以及算法分析。
题目描述
输入:一个未排序的整数数组 nums
。
输出:未在数组中出现的最小正整数。
示例:
输入: [1,2,0]
输出: 3
输入: [3,4,-1,1]
输出: 2
输入: [7,8,9,11,12]
输出: 1
方法一:索引作为哈希键
解题步骤
- 处理负数和零:由于我们只关心正数,可以先将所有非正整数替换为一个大于数组长度的值(例如
n+1
,其中n
是数组长度)。 - 利用索引标记:遍历数组,使用数组索引作为哈希键来标记存在的数字。具体操作是,对于每个数字
x
,如果1 <= x <= n
,则将索引x-1
的位置的数字设置为负数。 - 寻找结果:再次遍历数组,第一个索引位置
i
使得nums[i] > 0
的i + 1
就是缺失的最小正数。
代码示例
def firstMissingPositive(nums):
n = len(nums)
# 将所有的负数和零替换为n+1,n+1是一个不可能出现在合法输出中的数字
for i in range(n):
if nums[i] <= 0:
nums[i] = n + 1
# 使用数组索引作为哈希键,通过置负标记存在的数字
for i in range(n):
num = abs(nums[i])
if num <= n:
nums[num - 1] = -abs(nums[num - 1])
# 寻找第一个大于0的索引位置,即是缺失的最小正数
for i in range(n):
if nums[i]> 0:
return i + 1
# 如果数组中包含了1到n的所有数字,则缺失的第一个正数是n+1
return n + 1
# 示例调用
print(firstMissingPositive([1, 2, 0])) # 输出: 3
print(firstMissingPositive([3, 4, -1, 1])) # 输出: 2
print(firstMissingPositive([7, 8, 9, 11, 12])) # 输出: 1
算法分析
- 时间复杂度:O(N),其中 N 是数组长度。算法涉及几个线性扫描,每个扫描的时间复杂度都是O(N)。
- 空间复杂度:O(1)。除了输入数组外,没有使用额外的空间,所有操作均在原数组上进行。
方法二:排序后线性扫描
解题步骤
- 排序数组:首先对数组进行排序。
- 线性扫描:遍历排序后的数组,查找第一个缺失的最小正数。
代码示例
def firstMissingPositive(nums):
nums.sort()
target = 1
for num in nums:
if num == target:
target += 1
return target
# 示例调用
print(firstMissingPositive([1, 2, 0])) # 输出: 3
print(firstMissingPositive([3, 4, -1, 1])) # 输出: 2
print(firstMissingPositive([7, 8, 9, 11, 12])) # 输出: 1
算法分析
- 时间复杂度:O(N log N),主要时间开销来源于排序。
- 空间复杂度:O(1) 或 O(N),这取决于使用的排序算法。
方法三:使用哈希表
解题步骤
- 使用哈希表存储:将所有正数存储在哈希表中。
- 寻找最小正数:从 1 开始递增寻找不在哈希表中的最小正数。
代码示例
def firstMissingPositive(nums):
num_set = set(nums)
target = 1
while target in num_set:
target += 1
return target
# 示例调用
print(firstMissingPositive([1, 2, 0])) # 输出: 3
print(firstMissingPositive([3, 4, -1, 1])) # 输出: 2
print(firstMissingPositive([7, 8, 9, 11, 12])) # 输出: 1
算法分析
- 时间复杂度:O(N),虽然使用了哈希表,但构建哈希表和查询的总时间仍是线性的。
- 空间复杂度:O(N),需要额外的空间来存储哈希表。
总结
为了直观地比较解决LeetCode题目41 "缺失的第一个正数"的三种方法,下面的表格将展示它们在不同技术维度的性能和特点,包括时间复杂度、空间复杂度以及各自的优势和劣势。
特征 | 方法一:索引作为哈希键 | 方法二:排序后线性扫描 | 方法三:使用哈希表 |
---|---|---|---|
时间复杂度 | O(N) | O(N log N) | O(N) |
空间复杂度 | O(1) | O(1) 或 O(N) | O(N) |
优势 | - 不使用额外空间 - 快速且高效 - 直接在原数组上操作,不需要额外的数据结构 | - 实现简单 - 直观易理解 - 适用于不限制时间复杂度的场景 | - 实现简单 - 查找速度快 - 直接使用Python内置数据结构 |
劣势 | - 算法理解相对复杂 - 需要修改原数组作为标记 | - 时间复杂度较高,尤其是在数据量大时 - 空间复杂度依赖于排序算法 | - 空间开销大 - 需要额外空间存储所有正数 |
适用场景 | - 数据量大且对空间有严格限制时 - 需要在原地解决问题时 | - 数据预处理和排序成本低时 - 对算法执行时间要求不严格时 | - 空间充足时 - 需要快速实现和简洁代码时 |