題目地址:
https://www.lintcode.com/problem/first-missing-positive/description
給定一個數組,返回中第一個未出現在數組中的數。
思路是,通過不停的交換,儘量將值爲的數移到下標爲的位置上去,然後從左到右掃描即可。舉例:對於,我們先把交換到數組第個位置上去,得到,這樣這個數字就歸位了,接下來沒有地方可以去,就直接略過,接下來把交換到數組第個位置上去,得到,已經歸位,再把換過來的歸位,得到,接下來的掃描都不會產生交換。最後從左到右掃描看哪個數字沒出現即可。代碼如下:
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;
}
}
時間複雜度,空間。
算法正確性證明:
設數組長度爲,那麼在循環到某個位置時,做的swap的次數一定是有限的,且不會超過,這是因爲每swap一次,就會有一個數字歸位,歸位後那個數字就不會再被swap到了,所以最多的情況就是數組每個位置都swap了一遍,也就是次數不超過。所以while循環一定會退出,也就是說第一個for循環一定會在有限時間內結束。接下來第二個for循環遍歷到的第一個的數,說明在這個數組中不存在,所以返回。如果遍歷到末尾說明第一個missing正數是。
時間複雜度證明:
只需注意到swap最多隻會執行不超過次即可。因爲每swap一次都會使得一個數字歸位,而最多只能有個數字歸位。