1. 程式人生 > 其它 >LeetCode-困難進階-41-缺失的第一個正數-原地解決(C)

LeetCode-困難進階-41-缺失的第一個正數-原地解決(C)

技術標籤:Cleetcodec語言

文章首發及後續更新:https://mwhls.top/1615.html
新的更新內容請到mwhls.top檢視。
無圖/無目錄/格式錯誤/更多相關請到上方的文章首發頁面檢視。

這題是我解決的第一道困難的LeetCode,值得紀念。
而且還完成了進階要求!

題目

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

進階:你可以實現時間複雜度為 O(n) 並且只使用常數級別額外空間的解決方案嗎?

示例 1:

輸入:nums = [1,2,0]
輸出:3
示例 2:

輸入:nums = [3,4,-1,1]
輸出:2
示例 3:

輸入:nums = [7,8,9,11,12]

輸出:1

提示:

0 <= nums.length <= 300
-231 <= nums[i] <= 231 - 1

來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/first-missing-positive
著作權歸領釦網路所有。商業轉載請聯絡官方授權,非商業轉載請註明出處。

思路

  • 這題能滿足進階要求,但只是因為這題的nums[]陣列大小有限,如果nums[]大小不限,這題無法滿足常數項的額外空間。
  • 這題是找最小未出現的正整數,那麼如果nums[]的大小為numsSize,則最小未出現的正整數,一定在1~numsSize+1之間。
  • 為了記錄所有出現過的數,設定一個numsSize[]大小的hasAppeared[]陣列,用來記錄nums[]出現的數,且由於最小未出現正整數<=numsSize+1,hasAppeared[]只需要numsSize大小即可。
    • hasAppeared[n]裡的值,表示n+1是否出現過,用1表示出現過,非1表示未出現過。
      • C語言中,未初始化的陣列可能是隨機值,也可能是0,這題在LeetCode的編譯器裡直接用1表示不會出現問題。
  • 那麼在程式碼裡面只需要這麼做即可:
    • 設定一個numsSize大小的hasAppeared[]陣列。
    • 遍歷nums[],如果nums[pos]的值是<=numsSize的正整數,那麼就將hasAppeared[ nums[pos]-1 ]的值置為1。
    • 遍歷完nums[]後,再遍歷hasAppeared[],第一個非1的位置即是所求的未出現的最小正整數,如果全1,則是第numsSize+1為未出現的最小正整數。
  • 例如:
    • 對於nums[] = {1, 0, 2};hasAppeared[]的情況為{1, 1, ?}。第一個非1位hasAppeared[2],因此return 2+1,即pos+1
    • 對於nums[] = {1, 2, 3};hasAppeared[]的情況為{1, 1, 1}。全1,因此return 3+1,即numsSize+1。
      • 注:全1時的遍歷結束後,pos == numsSize,因此兩種情況均可return pos+1。
  • 進階:你可以實現時間複雜度為O(n)並且只使用常數級別額外空間的解決方案嗎?
    • 程式碼時間複雜度為O(n)+O(n),即O(n)。
    • 使用了n的不定空間。
      • 對於本題來說,numsSize不超過300,因此可以將長度為n的不定空間改成長度為300的空間,就可以滿足進階要求了。
    • 如果要實現原地解決的話,我的想法在現在的基礎上改進:
      • 依然是遍歷nums[],如果0<nums[pos]<=numsSize,就交換nums[pos]和nums[ nums[pos]-1 ],再將nums[pos]置1。
      • 然後對nums[]執行如上hasAppeared的操作。
    • 是的,我想完想法發現好簡單然後順便實現了!
    • 現在是隻需要兩個int就能解決了!
    • 改進完發現原來的還缺點東西,新的思路是這樣的:
      • 遍歷nums[],如果nums[pos] != pos+1,那麼交換nums[pos]與nums[ nums[pos]-1 ],並將pos--。
      • 結束後,遍歷一遍nums[],如果全符合nums[pos] == pos+1,就返回numsSize,否則返回pos+1。

程式碼-普通

/*
設定一個hasAppeared的int陣列,大小為numsSize。
如果出現了這個數,就將hasAppeared置1,將nums[]遍歷,
結束後,將hasAppeared遍歷,如果全為1就表明1~numsSize全出現了,返回numsSize+1
否則返回第一個非1的。
*/

int firstMissingPositive(int* nums, int numsSize){
    int *hasAppeared = (int*)malloc(sizeof(int)*numsSize);
    int pos;
    for(pos=0;  pos<numsSize;   pos++){
        if(nums[pos]<=numsSize && nums[pos]>0) hasAppeared[ nums[pos]-1 ] = 1;
    }
    for(pos=0;  pos<numsSize;   pos++){
        if(hasAppeared[pos] != 1) return pos+1;
    }
    return pos+1;
}

程式碼-進階

/*
遍歷nums[],如果nums[pos] != pos+1,那麼交換nums[pos]與nums[ nums[pos]-1 ],並將pos--。
結束後,遍歷一遍nums[],如果全符合nums[pos] == pos+1,就返回numsSize,否則返回pos+1。
*/

int firstMissingPositive(int* nums, int numsSize){
    int pos, temp;
    for(pos=0;  pos<numsSize;   pos++){
        if(nums[pos]<=numsSize && nums[pos]>0 && nums[pos]!=pos+1) {
            temp = nums[pos];
            nums[pos] = nums[ temp-1 ];
            nums[ temp-1 ] = temp;
            if(nums[pos] == nums[temp-1]) nums[pos]=-1;
            pos--;
        }
    }
    for(pos=0;  pos<numsSize;   pos++){
        if(nums[pos] != pos+1) return pos+1;
    }
    return pos+1;
}