BM53-缺失的第一个正整数

题目

给定一个无重复元素的整数数组nums,请你找出其中没有出现的最小的正整数。

进阶: 空间复杂度 O(1),时间复杂度 O(n)。

数据范围:

−2^31≤nums[i]≤2^31−1。

0≤len(nums)≤5∗10^5。

示例1

输入:[1,0,2]

返回值:3

示例2

输入:[-2,3,4,1,5]

返回值:2

示例3

输入:[4,5,6,8,9]

返回值:1


思路1:哈希表

n个长度的数组,没有重复,则如果数组填满了1~n,那么缺失n+1,如果数组填不满1~n,那么缺失的就是1~n中的数字。对于这种快速查询某个元素是否出现过的问题,还是可以使用哈希表快速判断某个数字是否出现过。

具体做法:

  • step 1:构建一个哈希表,用于记录数组中出现的数字。
  • step 2:从1开始,遍历到n,查询哈希表中是否有这个数字,如果没有,说明它就是数组缺失的第一个正整数,即找到。
  • step 3:如果遍历到最后都在哈希表中出现过了,那缺失的就是n+1。

代码1

import java.util.*;

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * @param nums int整型一维数组 
     * @return int整型
     */
    public int minNumberDisappeared (int[] nums) {
        int n = nums.length;
        HashMap<Integer, Integer> mp = new HashMap<Integer, Integer>();
        //哈希表记录数组中出现的每个数字
        for(int i = 0; i < n; i++) {
            mp.put(nums[i], 1);
        }
        int res = 1;
        //从1开始找到哈希表中第一个没有出现的正整数
        while(mp.containsKey(res)) {
            res++;
        }
        return res;
    }
}
  • 时间复杂度:O(n),第一次遍历数组,为O(n),第二次最坏从1遍历到n,为O(n)。
  • 空间复杂度:O(n),哈希表记录n个不重复的元素,长度为n。

思路2:原地哈希

前面提到了数组要么缺失1~n中的某个数字,要么缺失n+1,而数组正好有下标0~n−1可以对应数字1~n,因此只要数字1~n中某个数字出现,就可以将对应下标的值做一个标记,最后没有被标记的下标就是缺失的值。

具体做法:

  • step 1:可以先遍历数组将所有的负数都修改成n+1。
  • step 2:然后再遍历数组,每当遇到一个元素绝对值不超过n时,则表示这个元素是1~n中出现的元素,我们可以将这个数值对应的下标里的元素改成负数,相当于每个出现过的正整数,我们把与它值相等的下标都指向一个负数,这就是类似哈希表的实现原理的操作。
  • step 3:最后遍历数组的时候碰到的第一个非负数,它的下标就是没有出现的第一个正整数,因为它在之前的过程中没有被修改,说明它这个下标对应的正整数没有出现过。

代码2

import java.util.*;

public class Solution {
    public int minNumberDisappeared (int[] nums) {
        int n = nums.length;
        //遍历数组
        for (int i = 0; i < n; i++) {
            //负数全部记为n+1
            if (nums[i] <= 0) {
                nums[i] = n + 1;
            }
        }
        for (int i = 0; i < n; i++) {
            //对于1-n中的数字
            if (Math.abs(nums[i]) <= n) {
                //这个数字的下标标记为负数
                nums[Math.abs(nums[i]) - 1] = -1 * Math.abs(nums[Math.abs(nums[i]) - 1]);
            }
        }           
        for (int i = 0; i < n; i++) {
            //找到第一个元素不为负数的下标
            if (nums[i] > 0) {
                return i + 1;
            }
        }
        return n + 1;
    }
}
  • 时间复杂度:O(n),多次遍历数组,都是单层循环。
  • 空间复杂度:O(1),原地哈希,以索引为指向,没有额外空间。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值