手摸手提桶跑路——LeetCode41.缺失的第一个正数

113 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第9天,点击查看活动详情

题目描述

给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。

请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。

示例 1:

输入:nums = [1,2,0]
输出:3

示例 2:

输入:nums = [3,4,-1,1]
输出:2

示例 3:

输入:nums = [7,8,9,11,12]
输出:1

提示:

  • 1 <= nums.length <= 5 * 105

  • -231 <= nums[i] <= 231 - 1

解题思路

首先通过题目我们可以知道整数数组未排序,且需要找到的是最小的正整数,这成为我们偷懒的巨大绊脚石。

思来想去只能使用点常规手法了。

最简单直接的,我们首要的肯定要对这些整数进行统计,然后为了找到这个最小的正整数,我们还需要从1开始不断的”询问“当前的结果数组中是否存在该整数,一直找到结果数组中不存在并返回,干就完事了。

那么提到统计,一开始我是想到用 javascript 对象的排序属性进行数据的统计。在V8中,对象属性如果是数字,则会按从小到大升序排列。

详见:第一篇《Google V8 原理》之编译原理

随后通过 Object.keys 获取当前已存在的所有整数,后面觉得 Object.keys 又要遍历一遍,duck不必,于是就考虑仍旧用对象进行统计,通过属性判断指定的正整数是否存在于当前对象的key中:

  1. index = 1 开始,去 obj 里检查对象是否具有该属性, index in obj
  2. 如果存在,则返回 index
  3. 否则,index++,进入下一轮循环

那么我们都知道,javascript 中,通过 in 操作符去寻找一个属性时,是有可能往原型上检索这个属性的,为了避免这个无用的开销,我通过 Object.create(null) 去创建一个纯净对象,这样后续代码中我们就可以不用特意去绕过原型链上的属性,从而直接通过 in 操作符处理。

关于 Object.create(null) 的更多说明,推荐 详解Object.create(null) 

通过从1到n的不断检索,最终我们就可以检索到缺失的最小的正整数了。

话不多说,上菜!

题解

/** 
* @param {number[]} nums 
* @return {number} 
*/
var firstMissingPositive = function(nums) {
    const lens = nums.length, t = Object.create(null);
    for(let i=0; i<lens; ++i) {
        t[nums[i]]=1;
    }
    let index = 1;
    while(true) {
        if(index in t) {
            index++;
            continue;
        } else {
            return index;
        }
    }
};

结束语

LeetCode 中虚虚实实的,hard 未必困难,middle 未必容易,多挑战不同的题目,锻炼思维,即使不能顶峰相会,也不要陷入泥潭。