LeetCode 41. First Missing Positive

Given an unsorted integer array nums. Return the smallest positive integer that is not present in nums.

You must implement an algorithm that runs in O(n) time and uses O(1) auxiliary space.

Example 1:

复制代码
Input: nums = [1,2,0]
Output: 3
Explanation: The numbers in the range [1,2] are all in the array.

Example 2:

复制代码
Input: nums = [3,4,-1,1]
Output: 2
Explanation: 1 is in the array but 2 is missing.

Example 3:

复制代码
Input: nums = [7,8,9,11,12]
Output: 1
Explanation: The smallest positive integer 1 is missing.

Constraints:

  • 1 <= nums.length <= 105
  • -231 <= nums[i] <= 231 - 1

这题给了一个unsorted array of integers,可正可负,要求求出这个数组里没有的第一个正数。

最直观的方法就是把这个数组变成一个set,然后从1开始看它在不在这个set里。然而题目要求不能用extra space,就,不会。

hint说可以想想怎么把hashset换个方式hash一下,想不到。直接看了答案,牛,但是思路虽然简单但是写起来也kind of复杂。

大概的思路就是没有出现的第一个正数一定是在[1, len]之间,于是我们就可以把出现过的数字都hash到数组里对应的index上,比如数字n就可以hash到index n - 1。为啥是i - 1呢是因为最大可能是len,但是index是len - 1。所以大概就是遍历这个数组,如果nums[i]的值应该hash到的index上的值(也就是nums[nums[i] - 1])不等于nums[i],那就交换这两个数字。如果这个值<= 0或者>= len那就不需要考虑它们。(为什么不考虑 == len呢,其实考虑也行但是没必要?因为最后我们anyways都会return len + 1?这个待定......)

那么这里又有一个tricky point,就是如果单纯的swap的话,会出现一种情况,把小的数字从后面swap到前面,然后就被skip了,就不会被放到正确的位置上了。举个例子就是[-1,4,2,1,9,10],第一次swap 4和1,变成[-1,1,2,4,9,10],然后下一次swap 2和1,变成[-1,2,1,4,9,10],最后这个1一直没被放在正确的位置上就return 1了......于是又去研究了和答案的不同,发现可以通过在每次循环结束后再把i--,就可以再判断一次这个位置上的数字在不在正确的位置上,妙啊。但是这样的话需要在continue的那个if里面加上判断如果当前已经是正确位置了就不需要再swap了,不然就死循环了。

第一次successful submission

class Solution {
    public int firstMissingPositive(int[] nums) {
        // 0 1 2 3 4
        // 1 2 3 x 5
        int len = nums.length;
        for (int i = 0; i < len; i++) {
            if (nums[i] <= 0 || nums[i] >= len || nums[nums[i] - 1] == nums[i]) {
                continue;
            }
            swap(nums, nums[i] - 1, i);
            i--;
        }
        for (int i = 0; i < len; i++) {
            if (nums[i] != i + 1) {
                return i + 1;
            }
        }
        return len + 1;
    }

    private void swap(int[] nums, int index1, int index2) {
        int temp = nums[index1];
        nums[index1] = nums[index2];
        nums[index2] = temp;
    }
}

还有一种最popular的nested loop的方法,着实是不想看啊,太复杂了,for里面套个while。但是somehow看到一种easy to understand的方法,哦其实也跟上面这个差不多,把第一个for改成while,不swap的时候才++,本质是一样的,但是感觉这样确实没有i--这么tricky:https://leetcode.com/problems/first-missing-positive/solutions/17071/my-short-c-solution-o-1-space-and-o-n-time/comments/147659

以及这种思想好像叫做cyclic sort:https://leetcode.com/problems/first-missing-positive/solutions/17214/java-simple-solution-with-documentation/comments/1255253 着实是不想看了......

相关推荐
Dream it possible!8 小时前
LeetCode 热题 100_在排序数组中查找元素的第一个和最后一个位置(65_34_中等_C++)(二分查找)(一次二分查找+挨个搜索;两次二分查找)
c++·算法·leetcode
夏末秋也凉8 小时前
力扣-回溯-46 全排列
数据结构·算法·leetcode
南宫生8 小时前
力扣每日一题【算法学习day.132】
java·学习·算法·leetcode
柠石榴8 小时前
【练习】【回溯No.1】力扣 77. 组合
c++·算法·leetcode·回溯
Leuanghing8 小时前
【Leetcode】11. 盛最多水的容器
python·算法·leetcode
qy发大财8 小时前
加油站(力扣134)
算法·leetcode·职场和发展
qy发大财8 小时前
柠檬水找零(力扣860)
算法·leetcode·职场和发展
不想编程小谭13 小时前
力扣LeetCode: 2506 统计相似字符串对的数目
c++·算法·leetcode
01_15 小时前
力扣hot100——LRU缓存(面试高频考题)
leetcode·缓存·面试·lru
_Itachi__16 小时前
LeetCode 热题 100 73. 矩阵置零
算法·leetcode·矩阵