【Lintcode】189. First Missing Positive

題目地址:

https://www.lintcode.com/problem/first-missing-positive/description

給定一個數組,返回(0,1,2,3,...)(0,1,2,3,...)中第一個未出現在數組中的數。

思路是,通過不停的交換,儘量將值爲ii的數移到下標爲i1i-1的位置上去,然後從左到右掃描即可。舉例:對於(3,4,1,1)(3,4,-1,1),我們先把33交換到數組第33個位置上去,得到(1,4,3,1)(-1, 4, 3, 1),這樣33這個數字就歸位了,接下來1-1沒有地方可以去,就直接略過,接下來把44交換到數組第44個位置上去,得到(1,1,3,4)(-1, 1, 3, 4)44已經歸位,再把換過來的11歸位,得到(1,1,3,4)(1, -1, 3, 4),接下來的掃描都不會產生交換。最後從左到右掃描看哪個數字沒出現即可。代碼如下:

public class Solution {
    /**
     * @param A: An array of integers
     * @return: An integer
     */
    public int firstMissingPositive(int[] A) {
        // write your code here
        if (A == null || A.length == 0) {
            return 1;
        }
    
        for (int i = 0; i < A.length; i++) {
        	// 這裏的while循環的意思是,如果A[i]代表的數字“應該”在的位置上的數字不等於A[i],就將其換過去
            while (1 <= A[i] && A[i] <= A.length && A[A[i] - 1] != A[i]) {
                swap(A, A[i] - 1, i);
            }
        }
    
        for (int i = 0; i < A.length; i++) {
            if (A[i] != i + 1) {
                return i + 1;
            }
        }
        // 如果上面的for循環裏沒有return,說明每個數字都歸位了,
        // 那第一個missing的正數就是A.length + 1
        return A.length + 1;
    }
    
    private void swap(int[] A, int i, int j) {
        int tmp = A[i];
        A[i] = A[j];
        A[j] = tmp;
    }
}

時間複雜度O(n)O(n),空間O(1)O(1)

算法正確性證明:
設數組長度爲ll,那麼在循環到某個位置時,做的swap的次數一定是有限的,且不會超過ll,這是因爲每swap一次,就會有一個數字歸位,歸位後那個數字就不會再被swap到了,所以最多的情況就是數組每個位置都swap了一遍,也就是次數不超過ll。所以while循環一定會退出,也就是說第一個for循環一定會在有限時間內結束。接下來第二個for循環遍歷到的第一個A[i]i+1A[i]\ne i+1的數,說明i+1i+1在這個數組中不存在,所以返回i+1i+1。如果遍歷到末尾說明第一個missing正數是l+1l+1

時間複雜度證明:
只需注意到swap最多隻會執行不超過ll次即可。因爲每swap一次都會使得一個數字歸位,而最多只能有ll個數字歸位。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章