1. 程式人生 > >尋找不在陣列中最小的正整數 First Missing Positive

尋找不在陣列中最小的正整數 First Missing Positive

問題:給出一個無序的陣列,其中包含有任意的整數。現在要求返回不包含在陣列中的最小的正整數。

要求:時間複雜度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]);
            }
    }
};