41. 缺失的第一个正数

130 阅读2分钟

方法一:HashSet,TC:O(N) SC:O(N)

  • 扫一遍数组,把数组元素存到set里。
  • 从1开始计数,看在不在set中,返回第一个不在的。

方法二:原地哈希,TC:O(N) SC:O(1)

  • 利用idx范围和item的范围之间的关系
  • 由于是找正整数,正常情况下nums[idx] = idx + 1
  • 把元素归位,即交换。
  • idx + 1 != nums[idx] 的位即为不满足条件的,返回。
class Solution {
    public int firstMissingPositive(int[] nums) {
        for (int i = 0; i < nums.length; i++) {
            // nums[nums[i] - 1] != nums[i]防止死循环,如 1,3,3,3
            while (nums[i] != i + 1 
                    && nums[i] > 0 && nums[i] <= nums.length 
                    && nums[nums[i] - 1] != nums[i]) {
                int tmp = nums[nums[i] - 1];
                nums[nums[i] - 1] = nums[i];
                nums[i] = tmp;
            }
        }
        
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] != i + 1) {
                return i + 1;
            }
        }
        //如果nums数组内位置都正确
        return nums.length + 1;
    }
}



 /*
       只有在 nums[i] 是 [1, len] 之间的数;并且不在自己应该呆的位置:nums[i] != i + 1;
        并且它应该呆的位置没有被同伴占有(即存在重复值占有)(不然会死循环):nums[nums[i] - 1] != nums[i] 的时候才进行交换
        	
        为什么使用 while ? 因为交换后,原本 i 位置的 nums[i] 已经交换到了别的地方,
        交换后到这里的新值不一定是适合这个位置的,因此需要重新进行判断交换
        如果使用 if,那么进行一次交换后,i 就会 +1 进入下一个循环,那么交换过来的新值就没有去找到它该有的位置
         比如 nums = [3, 4, -1, 1] 当 3 进行交换后, nums 变成 [-1,4,3,1],
         此时 i == 0,如果使用 if ,那么会进入下一个循环, 这个 -1 就没有进行处理
        */
  • 典型错误 忘记范围、忘了死循环

image.png