LeetCode-困難進階-41-缺失的第一個正數-原地解決(C)
阿新 • • 發佈:2021-02-07
文章首發及後續更新: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]
提示:
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表示不會出現問題。
- hasAppeared[n]裡的值,表示n+1是否出現過,用1表示出現過,非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;
}