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

相关推荐
linsa_pursuer30 分钟前
快乐数算法
算法·leetcode·职场和发展
XuanRanDev36 分钟前
【每日一题】LeetCode - 三数之和
数据结构·算法·leetcode·1024程序员节
代码猪猪傻瓜coding37 分钟前
力扣1 两数之和
数据结构·算法·leetcode
南宫生2 小时前
贪心算法习题其三【力扣】【算法学习day.20】
java·数据结构·学习·算法·leetcode·贪心算法
passer__jw7673 小时前
【LeetCode】【算法】283. 移动零
数据结构·算法·leetcode
星沁城5 小时前
240. 搜索二维矩阵 II
java·线性代数·算法·leetcode·矩阵
一直学习永不止步5 小时前
LeetCode题练习与总结:赎金信--383
java·数据结构·算法·leetcode·字符串·哈希表·计数
劲夫学编程8 小时前
leetcode:杨辉三角
算法·leetcode·职场和发展
师太,答应老衲吧12 小时前
SQL实战训练之,力扣:2020. 无流量的帐户数(递归)
数据库·sql·leetcode
passer__jw76720 小时前
【LeetCode】【算法】208. 实现 Trie (前缀树)
算法·leetcode