尋找不在陣列中最小的正整數 First Missing Positive
阿新 • • 發佈:2019-01-27
問題:給出一個無序的陣列,其中包含有任意的整數。現在要求返回不包含在陣列中的最小的正整數。
要求:時間複雜度O(n),空間複雜度O(1)。
思路:如果不要求空間複雜度,可以用hash、map進行統計。但是現在,不允許藉助臨時空間。但是對於無序陣列,不借助空間怎麼可能統計的出來。
方法一:把輸入陣列自己作為臨時空間使用。
這一方法用了一個類似計數排序的技巧。把陣列下標看作一個數的hash值,把一個正數是否存在這一資訊儲存在該正數值對應的下標位置裡。但是不能夠覆蓋掉陣列本身的資料,所以利用負號這一標誌來代表該位置所對應下標數值的存在性。利用這個方法,就能夠做到把陣列本身作為自己的hash表。
在這麼做之前,要先陣列中沒有用的負數移到陣列最左邊去。
class Solution { public: int firstMissingPositive(int A[], int n) { if(n == 0) return 1; int k = seperate(A, n); //A[0..k] if(k == -1) return 1; //mark the index for(int i=0;i<=k;i++) { int value = abs(A[i]); if(value > k+1) continue; A[value-1] = - abs(A[value-1]); //防止重複取反導致記錄錯誤 } for(int i=0;i<=k;i++) { if(A[i] > 0) return i+1; } return k+2; } int seperate(int A[], int n) //返回正數序列的末尾座標 { int left = 0, right = n-1; while(left < right) { while(left < right && A[left] > 0) left++; while(left < right && A[right] <=0) right--; if(left < right) swap(A[left], A[right]); } if(A[left] > 0) return left; else return left-1; } void swap(int &a, int &b) { a = a^b; b = a^b; a = a^b; } };
方法二:利用桶排序的思想。將正整數放在對應的下標位置上。1放在A[0],2放在A[1]……由於不能用輔助空間,所以需要交換來完成放置。對於一個元素數值A[i],如果0<A[i]<n,那麼它的最終位置應該是A[A[i]-1],因此交換A[i],A[A[i]-1]即可;如果不是正整數或是超過陣列下標範圍,那麼就沒有可放置的最終位置(這個數也必然不會是最終要找的數)。
class Solution { public: int firstMissingPositive(int A[], int n) { bucket(A, n); for(int i=0;i<n;i++) if(A[i] != i+1) return i+1; return n+1; } void bucket(int A[], int n) { for(int i=0;i<n;i++) while(A[i] != i+1) { if(A[i] <= 0 || A[i] > n || A[i] == A[A[i]-1]) break; swap(A[i], A[A[i]-1]); } } };