leetcode:41. 缺失的第一个正数

题目描述

  • leetcode:41. 缺失的第一个正数

题目解析

leetcode:41. 缺失的第一个正数_第1张图片

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {

    }
};

题目解析

先分析数据量&题意

  • 1 < = n u m s . l e n g t h < = 5 ∗ 1 0 5 1 <= nums.length <= 5 * 10^5 1<=nums.length<=5105

    • 时间复杂度为O(N * logN)
    • 但是题目中要求了时间复杂度O(N),空间复杂度O(1)
    • 时间复杂度O(N):所有数只看一遍
    • 空间复杂度O(1),有两种情况可以达成
      • 只用几个辅助变量
      • 利用原数组
  • − 2 31 < = n u m s [ i ] < = 2 31 − 1 -2^{31} <= nums[i] <= 2^{31} - 1 231<=nums[i]<=2311

    • 有负数出现。
    • 题目要求返回缺失的最小正整数,正整数1、2…

原地哈希

  • 对于一个长度为n的数组,其中没有出现的最小正整数只能在 [ 1 , n + 1 ] [1,n+1] [1n+1]中。这是因为如果 [ 1 , n ] [1,n] [1,n]出现了,那么答案是 n + 1 n + 1 n+1,否则答案就是 [ 1 , n ] [1, n] [1,n]中没有出现的最小正整数

    • 那么我们可以遍历数组,然后将对应的数据填充到对应的位置上去,比如 1 就填充到 nums[0] 的位置, 2 就填充到 nums[1]
    • 如果填充过程中, nums[i] < 1 && nums[i] > len,那么直接舍弃
    • 填充完成,我们再遍历一次数组,如果对应的 nums[i] != i + 1,那么这个 i + 1 就是缺失的第一个正数
  • 比如 nums = [7, 8, 9, 10, 11], len = 5

    • 我们发现数组中的元素都无法进行填充,直接舍弃跳过,
    • 那么最终遍历数组的时候,我们发现 nums[0] != 0 + 1,即第一个缺失的是 1
  • 比如 nums = [3, 1, 2], len = 3

    • 填充过后,我们发现最终数组变成了 [1, 2, 3],每个元素都对应了自己的位置,那么第一个缺失的就是 len + 1 == 4

怎么做?

class Solution {
public:
    int firstMissingPositive(vector<int>& arr) {
        int L = 0;  //盯着的位置
        int R = arr.size(); //垃圾区左边界,R+1也是最好的预期
        while (L != R){  //垃圾区和有效区还没有撞上
            if(arr[L] == L + 1){  // 当前数呆在它应该在的位置
                L++;  //有效区左扩
            }else if(arr[L] <= L || arr[L] > R || arr[arr[L] - 1] == arr[L]){  // 应该去垃圾区的情况:当前数 <= L   ,当前数 > 右边界 ,出现了重复
                swap(arr[L], arr[--R]);
            }else{
                swap(arr[L], arr[arr[L] - 1]);
            }
        }
        
        return L + 1;
    }
};

类似题目

题目 思路
leetcode:41. 无序数组中缺失的第一个正整数(数组数据范围[-oo, +oo]) First Missing Positive 应该去垃圾区的情况:当前数 <= L ,当前数 > 右边界 ,出现了重复
leetcode:268. 无序数组缺失的那个数(数组数据范围在[0, n],数据长度为n) Missing Number 如果我们补充一个完整的数组和原数组进行组合,那所求解的问题就变成了 只出现一次的数字。
leetcode:448. 无序数组缺失的那个数(数组数据范围在[1, n],数据长度为n) Find All Numbers Disappeared in an Array 标记法:在原数组上进行一次遍历,在遍历的过程中,将遇到的元素所对应的index下的元素标记为负。最终哪些index下的元素没有被标记的则说明,这个index对应额元素没有出现过。置换法
leetcode:136. 无序数组出现一次的数字(出现一次的数字有一个,其他出现两次)Single Number 异或相消,剩下来的就是想要的
leetcode:137. 无序数组出现一次的数字(出现一次的数字有一个,其他出现三次) II Single Number IISingle Number II 对于出现三次的数字,各个二进制位出现的次数都是3的倍数。因此,统计所有数字的各二进制位中1的出现次数,并对3求余,结果则为只出现一次的数字(通用解法)。实现:对int的32个位每个位进行依次判断该位1的个数求余3后是否为1,如果为1说明结果该位二进制为1可以将结果加上去。最终得到的值即为答案。
leetcode:260. 无序数组出现一次的数字(出现一次的数字有两个,其余出现两次)Single Number III 先将元素分成两组,然后每组包含一个目标值,那么异或之后,每组得到一个目标值。比如a,b,a,b,c,d,e,f,e,f,分组后;A组:a, a , b, b, c 异或得到 c;B组:e, e, f, f, d 异或得到 d
leetcode:287.无序数组出现多次的数字(只有一个出现多次,其他数出现一次) (数组数据范围在[1, n],数据长度为n+1) Find the Duplicate Number 因为不允许修改原数组,所以不能用标记法。而一般对于链表,数组中要求找重复的数字或者节点,都可以考虑用快慢指针的方法来解。注意,相遇处不一定是
leetcode:442.无序数组出现两次的整数(每个数出现一次或者两次,数组数据范围在[1, n])) Find All Duplicates in an Array 标记法:对于每个nums[i],我们将其对应的nums[nums[i] - 1]取相反数,如果其已经是负数了,说明之前存在过,我们将其加入结果res中即可;置换法: 将nums[i]置换到其对应的位置nums[nums[i]-1]上去,最后在对应位置检验,如果nums[i]和i+1不等,那么我们将nums[i]存入结果res中即可
leetcode:645. 无序数组,有一个数字重复出现了一次,从而造成了另一个数字的缺失,请找出重复的数字和缺失的数字(数据范围在[1, n],数据长度为n) Set Mismatch 假设每个人各司其职, 那么每个岗位上就是相应的人员,并且各司其职, 但是现在混入了一个;闲杂人等, 他又害怕被人发现, 于是他就别人的岗位上站着, 结果等着等着, 这个岗位上应该来的人来了;他一看, 自己掩饰不过去了(毕竟人家不会跑到别的岗位上,抢别人的活干, 于是他就这么一直碰运气。 一直走到那个没来上岗的那个人的岗位上去, 这样谁都不会发现他是的闲杂人等.而且每个岗位上都满员了.
leetcode:142. 环形链表 II
leetcode:540. 有序数组中的单一元素(其他出现两次) 二分
leetcode:389. 字符t比字符s多出的那个数 Find the Difference 异或
765. 情侣牵手Couples Holding Hands
565. 数组嵌套 Array Nesting
1207. 独一无二的出现次数 先统计数字出现的频率,然后看相同频率是否重复出现

你可能感兴趣的:(算法与数据结构,leetcode,算法,职场和发展)