题目描述
给你一个未排序的整数数组
nums
,请你找出其中没有出现的最小的正整数。请你实现时间复杂度为
O(n)
并且只使用常数级别额外空间的解决方案。示例 1:输入:nums = [1,2,0] 输出:3 解释:范围 [1,2] 中的数字都在数组中。
示例 2:输入:nums = [3,4,-1,1] 输出:2 解释:1 在数组中,但 2 没有。
示例 3:输入:nums = [7,8,9,11,12] 输出:1 解释:最小的正数 1 没有出现。
提示:
1 <= nums.length <=
-
<= nums[i] <=
- 1
解题思路
-
处理不合法的元素:首先,遍历数组,将所有小于等于0或大于数组长度
n
的元素标记为n + 1
,因为这些元素不影响我们寻找缺失的最小正整数。 -
标记出现的正整数:
遍历数组,对于每个元素的绝对值num
,如果num
在范围[1, n]
内,说明这个数是合法的,可以作为索引来标记;使用负号标记nums[num - 1]
,表示数字num
出现在数组中。 -
查找未出现的正整数:
再次遍历数组,找到第一个值为正的索引i
,返回i + 1
,这就是缺失的最小正整数;如果所有位置的值都是负的,说明数组中包含了[1, n]
范围内的所有整数,因此返回n + 1
。
复杂度分析
- 时间复杂度:O(n),遍历数组三次,每次遍历的时间复杂度都是 O(n)。
- 空间复杂度:O(1),只使用了常数级别的额外空间,修改了原数组。
代码实现
package org.zyf.javabasic.letcode.hot100.ordinaryarray;
/**
* @program: zyfboot-javabasic
* @description: 缺失的第一个正数
* @author: zhangyanfeng
* @create: 2024-08-21 22:38
**/
public class FirstMissingPositiveSolution {
public int firstMissingPositive(int[] nums) {
int n = nums.length;
// 步骤 1:处理不合法的元素
// 将不在范围 [1, n] 内的元素标记为 n+1(超出范围的数)
for (int i = 0; i < n; i++) {
if (nums[i] <= 0 || nums[i] > n) {
nums[i] = n + 1;
}
}
// 步骤 2:使用原地哈希方法标记出现的正整数
for (int i = 0; i < n; i++) {
int num = Math.abs(nums[i]);
if (num <= n) {
// 标记 num 位置的值为负数,表示 num 出现过
if (nums[num - 1] > 0) {
nums[num - 1] = -nums[num - 1];
}
}
}
// 步骤 3:查找第一个未出现的正整数
for (int i = 0; i < n; i++) {
if (nums[i] > 0) {
return i + 1;
}
}
// 如果所有位置都被标记,则返回 n+1
return n + 1;
}
public static void main(String[] args) {
FirstMissingPositiveSolution solution = new FirstMissingPositiveSolution();
// 测试用例 1
int[] nums1 = {1, 2, 0};
System.out.println(solution.firstMissingPositive(nums1)); // 输出: 3
// 测试用例 2
int[] nums2 = {3, 4, -1, 1};
System.out.println(solution.firstMissingPositive(nums2)); // 输出: 2
// 测试用例 3
int[] nums3 = {7, 8, 9, 11, 12};
System.out.println(solution.firstMissingPositive(nums3)); // 输出: 1
}
}
具体可参考:https://zyfcodes.blog.csdn.net/article/details/141401712