Given an unsorted integer array, find the first missing positive integer.
For example,
Given [1,2,0]
return 3
,
and [3,4,-1,1]
return 2
.
Your algorithm should run in O(n) time and uses constant space.
» Solve this problem
O(n^2)的算法是最直观的思路,枚举1~n,然后检查是否存在。
O(nlogn)的算法也不难想到,对数组排序,然后遍历数组。
如果允许O(n)的空间,利用一个hash数组,也能够实现O(n)的算法。
现在题目给予的是常量空间,要求实现O(n)的算法。
网上很多同学的blog都给出了基于hash的思想的一个O(n)的算法。
大致思路:
既然不允许使用额外的数组作为hash数组,那么就考虑让原数组多带点信息。
第一步,假设原数组都是正数,那么我们可以考虑将相应位置的正数变成负数来表示该位置已经出现过。听上去有些抽象,举个例子:
0 1 2 3 4 5 6 7 8 9
A = 9 7 6 5 3 1 4 5 8 4
由于数组下标都是从0到n-1,而我们要考虑的是1到n,所以要从[0, n-1]映射到[1, n]。
|A[0]| (绝对值符号) = 9,所以我们将A[9 - 1([1,n]映射到[0, n-1])] 即A[8]置为-A[8]。
0 1 2 3 4 5 6 7 8 9
A = 9 7 6 5 3 1 4 5 -8 4
|A[1]| = 7,A[7-1]即A[6]=-A[6]。
0 1 2 3 4 5 6 7 8 9
A = 9 7 6 5 3 1 -4 5 -8 4
|A[2]|=6,A[5]=-A[5]。
0 1 2 3 4 5 6 7 8 9
A = 9 7 6 5 3 -1 -4 5 -8 4
最终:
0 1 2 3 4 5 6 7 8 9
A = -9 7 -6 -5 -3 -1 -4 -5 -8 4
第二步,很简单了,遍历数组A,看哪一位不是负数,则该位下标+1则是所求。
对上例,A[1]=7,所以First Missing Positive是2。
假设存在负数和0,则可以将这些全部置为一个无穷大(或者N+1)的正数即可。在置反时,如果A[i]超出了范围,则不理会。
例如:
0 1 2 3 4 5 6 7 8 9
A = 9 7 6 5 3 1 4 -5 8 4
预处理后变为:
0 1 2 3 4 5 6 7 8 9
A = 9 7 6 5 3 1 4 11(N+1) 8 4
最终:
0 1 2 3 4 5 6 7 8 9
A = -9 7 -6 -5 -3 -1 -4 -11 -8 4
我采用了另外一种方法。
大致思路:
第一步,遍历数组,如果A[i]不等于i+1,也就是相应数字没有出现在该出现的位置上,则交换A[i]和A[A[i] - 1],直到A[i]<=0或者A[i]>N或者A[i]==i+1为止。
第二步,遍历数组,第一个满足A[i] != i+1的i,First missing positive为i+1。
举例说明:
0 1 2
A = 0 1 3
A[0] = 0,满足A[i]<=0的条件,不作变动。
A[1] = 1,交换A[1]和A[A[1] - 1]即A[0],得到:
0 1 2
A = 1 0 3
A[2] = 3,满足A[i] == i + 1的条件,不作变动。
遍历数组,发现A[1] != 2,因此First Missing Positive为2.
P.S.
0 1
A = 1 1
会陷入不断的交换之中,因此需要再加一个终止条件:上次交换的数和这次的相同,则没必要交换。
class Solution {
public:
int firstMissingPositive(int A[], int n) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
for (int i = 0, temp = -1; i < n; i++) {
while (A[i] - 1 >= 0 && A[i] - 1 < n && A[i] - 1 != i) {
swap(A, i, A[i] - 1);
if (A[i] == temp) {
break;
}
else {
temp = A[i];
}
}
}
for (int i = 0; i < n; i++) {
if (A[i] - 1 != i) {
return i + 1;
}
}
return n + 1;
}
private:
void swap(int A[], int idx1, int idx2) {
A[idx1] ^= A[idx2];
A[idx2] ^= A[idx1];
A[idx1] ^= A[idx2];
}
};