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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值