41. 缺失的第一个正数
给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。
进阶:你可以实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案吗?
示例 1:
输入:nums = [1,2,0]
输出:3
示例 2:
输入:nums = [3,4,-1,1]
输出:2
示例 3:
输入:nums = [7,8,9,11,12]
输出:1
提示:
0 <= nums.length <= 300
-231 <= nums[i] <= 231 - 1
class Solution {
public int firstMissingPositive(int[] nums) {
//1. 空间复杂度为n的方法: 建立一张长度为 nums.length+1 的'桶'表即可
//2.使用原表记录数据,数字是否存在通过-号和下标判断。这样在记录数时不会改变未遍历的数
// 可以先将所有的负数初始化为1,初始化为0则无法取反存值(或者需要多出一步判断)
// 取1不管在存数之前该位置有没有数据,都可以直接取反即可
// 取数时 对数取绝对值Math.abs()
// 设置为负时需要判断是否下标越界
// 存数时判断:if < 0,则说明已经存过数了,不作操作,> 0 则对数取反(负)
// 位置下标 == 数值 - 1
// 先将数字1排除
boolean flag = false; // 判断有没有1的标志
for (int i = 0; i < nums.length; i++) {
if (nums[i] == 1) {
flag = true;
break;
}
}
if (!flag) return 1;
// 将所有的非正数设置为1
for(int i = 0; i < nums.length; i++) {
if (nums[i] <= 0) nums[i] = 1;
}
// 同时应该将0下标处 取反,表示1是存在的
nums[0] = -1 * nums[0];
// 遍历元素,两种情况需要操作,|x| > 1
for (int i = 0; i < nums.length; i++) {
int x = nums[i];
if ((x > 1) && (x <= nums.length)) { // 这里和下面的判断都强制重复赋值,省去了判断
nums[x-1] = -1 * Math.abs(nums[x-1]);
}
if ((x < -1) && (-x <= nums.length)) { // 当前位置是已经被修改过一次的数
nums[Math.abs(x) - 1] = -1 * Math.abs(nums[Math.abs(x) - 1]);
}
// 最后修改完判断:是不是恰巧修改了自己
// if (x == nums[i] && x > 0 ) nums[i] = 1; // 如果是>1的情况
// 没有修改自己,也有可能是本身是负数
}
for (int i = 0; i < nums.length; i++) {
if (nums[i] > 0) { // 如果某位置处为1,则说明存在 缺失
return i+1;
}
}
return nums.length + 1;
}
}