LeetCode 41. 缺失的第一個正數

ShacooKL發表於2024-10-11

給你一個未排序的整數陣列 nums ,請你找出其中沒有出現的最小的正整數。

請你實現時間複雜度為 O(n) 並且只使用常數級別額外空間的解決方案。

示例 1:

輸入:nums = [1,2,0]
輸出:3
解釋:範圍 [1,2] 中的數字都在陣列中。

示例 2:

輸入:nums = [3,4,-1,1]
輸出:2
解釋:1 在陣列中,但 2 沒有。

示例 3:

輸入:nums = [7,8,9,11,12]
輸出:1
解釋:最小的正數 1 沒有出現。

提示:

  • 1 <= nums.length <= 105
  • -231 <= nums[i] <= 231 - 1

思路

約束:

  1. 未排序 要求O(n) 不能使用排序演算法 且對順序有一定要求 考慮雜湊表(集合)
  2. 常數級別的空間 不能使用雜湊表(集合)

分析:

​ 考慮答案範圍,最小值可能是1,如所有數都大於1;當nums[i]=i+1時,答案取最大值,最大值是nums.size+1。故答案範圍在[1,nums.size+1]。所以只需要從小到大遍歷該範圍,第一個未出現的數字就是答案。

​ 考慮如果範圍內某一數值x出現,則記錄該值出現,自然想到集合或者雜湊

難點:需要雜湊表(集合),但不能使用雜湊表(集合)

解決:

​ 如何記錄?利用nums陣列,[1,nums.size+1] 需要n個位置記錄,所以讓nums[i]記錄i-1是否出現

​ 如果x在範圍裡,則用nums[x-1]儲存該數字,原來的資料怎麼辦?將二者位置交換即可,交換之後,新資料有兩種情況,在範圍內,則需要繼續交換,出現迴圈,考慮該操作有可能不停止嗎,考慮一直在範圍內的情況,也就是換了之後,目標位置符合條件nums[x-1]=x,同時本來的位置數值換過去也符合,也就是nums[i]=x, 出現了重複的數字,需要考慮該情況;不在範圍內則停止處理。

eg: [3,4,1,-1]

i=0

​ 第一次交換 [1,4,3,-1]

交換後1在範圍內,繼續交換[1,4,3,-1] (其實1已經在位置上了,可以省略)

​ 交換後1在範圍內,nums[0]=1,不需要繼續交換

i=1

​ 第一次交換[1,-1,3,4]

i=2

i=3

結果[1,-1,3,4]

遍歷結果 第一個不符合 nums[i]!=i+1的 i+1就是答案

實現:

int firstMissingPositive(vector<int>& nums) {
    for(int i=0;i<nums.size();i++) {
        //進行雜湊
        while(nums[i]>0&&nums[i]<=nums.size()&&nums[i]!=i+1) {
            int t = nums[i];
            //需要考慮的死迴圈情況
            if(nums[i]==nums[t-1])
                break;
            nums[i]=nums[t-1];
            nums[t-1] = t;
        }
    }
    for(int i=0;i<nums.size();i++) {
        //找到第一個不符合條件的就是答案
        if(nums[i]!=i+1) {
            return i+1;
        }
    }

    return nums.size()+1;

}

相關文章