leetcode41-缺失的第一个正数

原题

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

示例 1:

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

示例 2:

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

示例 3:

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

提示:

你的算法的时间复杂度应为O(n),并且只能使用常数级别的额外空间。

解法

该题解同步发于leetcode:Java:比官方题解少一次循环

思想

见代码部分

代码

首先这道题有一个隐含条件:如果数组的大小为n,则缺失的第一个正数一定小于或等于n+1(取值最大的情况是数组中的数从1开始连续)

如果不限制常数级别的额外空间,可以使用bitmap的思想去做,如下:

class Solution {
    public int firstMissingPositive(int[] nums) {
        int n = nums.length;
        //下标对应出现的数-1
        int[] exist = new int[n+1];
        for(int i:nums){
            if(i<=0 || i > n) continue;
            exist[i-1] = 1;
        }
        for(int i = 0;i<n+1;i++){
            if(exist[i]==0) return i+1;
        }
        return 0;
    }
}

但是限制了常数级别的额外空间,可以思考一种替换bitmap的原地解法:

既然要原地,肯定需要在原数组上判断当前下标代表的正数是否出现,但又不能修改它的值,因为遍历的时候会用到,可以想到通过修改它的符号来判断。相较于新建一个数组作为bitmap去重的区别是,存在不存在不通过1或0标识,而是通过正负号标识(负号标识出现过,正号标识没出现)

但是数组中存在一些数原来就是负号的,可以先遍历一次让它们都变成正数,0也要变成一个正数,否则无法通过改变符号识别该下标代表的元素是否出现。但变成哪个正数值得考量,否则再次遍历有可能把他们当作数组中原有的数处理,那么就可以把它们设为n+1,因为n+1大于数组的长度,不会映射到数组中的位,可以不进行处理:

class Solution {
    public int firstMissingPositive(int[] nums) {
        int n = nums.length;
        //先将原来的负数的数置为 `n+1`
        for(int i = 0; i < nums.length ; i++){
            if(nums[i]<=0 ) {
                nums[i] = n+1;
            }
        }
        for(int i = 0; i < nums.length ; i++){
            int num = Math.abs(nums[i]);
            //绝对值大于数组长度的不处理
            if(num<=n && nums[num-1]>0) 
                nums[num-1] = -nums[num-1];
        }
        for(int i = 0;i<n;i++){
            if(nums[i]>0) return i+1;
        }
        return n+1;
    }
}

成功将官方题解的O(4N)优化成O(3N)~~~

原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/leetcode41-%e7%bc%ba%e5%a4%b1%e7%9a%84%e7%ac%ac%e4%b8%80%e4%b8%aa%e6%ad%a3%e6%95%b0/

(0)
彭晨涛彭晨涛管理者
上一篇 2020年5月10日
下一篇 2020年5月11日

相关推荐

  • leetcode209-长度最小的子数组

    原题 给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。 示例: 输入: s = …

    算法 2019年11月20日
    0170
  • leetcode744-寻找比目标字母大的最小字母

    原题 给定一个只包含小写字母的有序数组letters 和一个目标字母 target,寻找有序数组里面比目标字母大的最小字母。 数组里字母的顺序是循环的。举个例子,如果目标字母tar…

    算法 2020年1月5日
    0210
  • leetcode122-买卖股票的最佳时机II

    原题 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 注意: 你不能同…

    算法 2020年2月7日
    080
  • leetcode295-数据流的中位数

    原题 中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。 例如, [2,3,4] 的中位数是 3 [2,3] 的中位数是 (2 + 3) / 2 = 2.…

    算法 2020年2月12日
    0100
  • 蓝桥杯试题-翻硬币

    原题 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 小明正在玩一个“翻硬币”的游戏。 桌上放着排成一排的若干硬币。我们用 * 表示正面,用 o 表示反面(是小写…

    算法 2020年3月1日
    0140
  • 程序员面试金典08.01-三步问题

    原题(来源Leetcode) 三步问题。有个小孩正在上楼梯,楼梯有n阶台阶,小孩一次可以上1阶、2阶或3阶。实现一种方法,计算小孩有多少种上楼梯的方式。结果可能很大,你需要对结果模…

    算法 2020年6月19日
    04560
  • leetcode24-两两交换链表中的节点

    原题 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。 示例: 给定 1->2->3->…

    算法 2020年1月20日
    0200
  • leetcode622-设计循环队列

    设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。 循环队列的一个好处是…

    算法 2019年11月24日
    0130
  • leetcode5-最长回文子串

    原题 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。 示例1: 输入: "babad" 输出: "bab" 注意: "aba" 也是一个有…

    算法 2020年2月20日
    0110
  • leetcode322-零钱兑换

    原题 给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。 示例 1…

    算法 2020年3月8日
    0150

发表回复

登录后才能评论