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 着实是不想看了......

相关推荐
烦躁的大鼻嘎28 分钟前
模拟算法实例讲解:从理论到实践的编程之旅
数据结构·c++·算法·leetcode
祁思妙想1 小时前
10.《滑动窗口篇》---②长度最小的子数组(中等)
leetcode·哈希算法
alphaTao2 小时前
LeetCode 每日一题 2024/11/18-2024/11/24
算法·leetcode
kitesxian2 小时前
Leetcode448. 找到所有数组中消失的数字(HOT100)+Leetcode139. 单词拆分(HOT100)
数据结构·算法·leetcode
jiao_mrswang4 小时前
leetcode-18-四数之和
算法·leetcode·职场和发展
王燕龙(大卫)4 小时前
leetcode 数组中第k个最大元素
算法·leetcode
Swift社区13 小时前
LeetCode - #139 单词拆分
算法·leetcode·职场和发展
Dong雨15 小时前
力扣hot100-->栈/单调栈
算法·leetcode·职场和发展
trueEve16 小时前
SQL,力扣题目1369,获取最近第二次的活动
算法·leetcode·职场和发展
九圣残炎18 小时前
【从零开始的LeetCode-算法】3354. 使数组元素等于零
java·算法·leetcode