zoukankan      html  css  js  c++  java
  • 【LeetCode-数组】缺失的第一个正数

    题目描述

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

    输入: [1,2,0]
    输出: 3
    
    输入: [3,4,-1,1]
    输出: 2
    
    输入: [7,8,9,11,12]
    输出: 1
    

    说明: 你的算法的时间复杂度应为O(n),并且只能使用常数级别的额外空间。
    题目链接: https://leetcode-cn.com/problems/first-missing-positive/
    做这一题之前,可以先做一下找到所有数组中消失的数字(思路2)

    思路

    使用哈希表来做,题目要求常数级别的额外空间,所以不能额外定义哈希表,但我们可以就在输入数组上构建哈希表。遍历数组,假设当前的元素为 nums[i],由于是找出 [1, n] 之间未出现的最小整数,所以,我们将 nums[abs(nums[i])-1] 设为负数,使用 abs(nums[i]) 的原因是因为 nums[i] 可能在之前的遍历过程中以及被设为负数了,但下标是一个大于等于 0 的数字,所以需要取绝对值。例如,假设 nums[1] = 3,nums[2] = 6,那么遍历到 nums[1] 时,我们将 nums[2] 设为 -6(nums[nums[1]-1] = -nums[nums[1]-1]),代表 2+1=3 出现过。当遍历结束时,我们再遍历一遍 nums,如果 nums[i]>=0 的话,说明 i+1 没有在 nums 中出现,返回 i+1。

    还有一个问题,就是输入的 nums 中可能包含负数。比如,nums 中包含 -1 但不包含 1,那么我们将 nums[abs(-1)-1] 设为了负数,表明 1 出现了,但实际上 1 并没有出现。这个问题的解决办法是:我们首先对输出数组 nums 遍历一遍,将其中的负数变为 0,然后在将 nums[abs(nums[i])-1] 设为负数的过程中,如果 nums[abs(nums[i])-1]==0,我们就将 nums[abs(nums[i])-1] 设为 -(num.size()+1),这样的话,在后序的过程中,nums[abs(nums[i])-1] 不会对其他的元素产生影响。具体代码如下:

    class Solution {
    public:
        int firstMissingPositive(vector<int>& nums) {
            for(int i=0; i<nums.size(); i++){ // 将负数转为0
                if(nums[i]<0) nums[i]=0;
            }
    
            for(int i=0; i<nums.size(); i++){ // 将nums[abs(nums[i])-1]设为-1
                int idx = abs(nums[i])-1;
                if(idx>=0 && idx<nums.size()){
                    if(nums[idx]==0) nums[idx]=-nums.size()-1;
                    else nums[idx] = -abs(nums[idx]); //这样可以保证一个数nums[i]出现多次时,nums[abs(nums[i])-1]一直为负数
                }
            }
    
            for(int i=0; i<nums.size(); i++){
                if(nums[i]>=0) return i+1;
            }
            return nums.size()+1;
        }
    };
    
    • 时间复杂度:O(n)
    • 空间复杂度:O(1)

    还可以这样写:
    先将小于等于 0 的元素转为数组中出现的任意一个正数,然后求解。代码如下:

    class Solution {
    public:
        int firstMissingPositive(vector<int>& nums) {
            if(nums.empty()) return 1;
    
            int t = 0;  // 任意的一个正数
            for(int i=0; i<nums.size(); i++){
                if(nums[i]>0){
                    t = nums[i];
                    break;
                }
            }
            if(t<=0) return 1;
    
            for(int i=0; i<nums.size(); i++){
                if(nums[i]<=0) nums[i]=t;  // 将小于等于0的数转为t
            }
    
            for(int i=0; i<nums.size(); i++){
                if(abs(nums[i])-1>=0 && abs(nums[i])-1<nums.size()){
                    nums[abs(nums[i])-1] = -abs(nums[abs(nums[i])-1]);
                }
            }
    
            for(int i=0; i<nums.size(); i++){
                if(nums[i]>=0) return i+1;
            }
            return nums.size()+1;
        }
    };
    

    这种写法个人感觉更容易理解,时间复杂度也是 O(n)。

    • 时间复杂度:O(n)
    • 空间复杂度:O(1)

    相关题目

    1、找到所有数组中消失的数字:https://www.cnblogs.com/flix/p/12857693.html

  • 相关阅读:
    RedHat Linux下利用sersync进行实时同步数据
    curl网站开发指南
    常用命令
    Linux 查看CPU信息、机器型号等硬件信息
    -bash: crontab: command not found(转)
    端口映射工具--socat
    左右半透明的无缝滚动
    js学习笔记33----DOM操作
    Framework 7 之 给Picker Modal 添加半透明背景
    网页嵌入自定义字体方法
  • 原文地址:https://www.cnblogs.com/flix/p/12969036.html
Copyright © 2011-2022 走看看