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.
分析:题目要求找出第一个消失的正整数,而且有空间复杂度要求。考虑用hash表,但是就满足条件了。而用排序,时间复杂度又变成了O(nlogN)。最后发现能够以数字自身来作为hash结构存储,同时发现对于空间复杂度有要求的,往往可以去考虑交换操作。
思路:遍历数组,对于每一个位置 i 进行深度交换,将val = A[i]放到位置A[i] - 1上。其实现结构有三种,写法不同,但是思路相同,有的看起来很简洁。
class Solution {
public:
int firstMissingPositive(int A[], int n) {
if(A == NULL || n == 0) return 1;
int i = 0;
while(i < n) {
int pos = A[i] - 1;
if(pos >= 0 && pos < n && A[pos] != A[i]) {
swap(A[i], A[pos]);
} else {
i++;
}
}
for(int i = 0; i < n; i++) {
if(i + 1 != A[i]) return i + 1;
}
return n + 1;
}
void swap(int &a, int &b) {
int tmp = a;
a = b;
b = tmp;
}
};
对于将A[i]放到合适位置的代码,也可以用两个while实现,只不过上面的代码更优雅
while(i < n) {
int pos = A[i] - 1;
while(pos >= 0 && pos < n && A[pos] != A[i]) {
swap(A[i], A[pos]);
pos = A[i] - 1;
}
i++;
}
很显然,改进成for + while又比上面的代码好
for(int i = 0; i < n; i++) {
int pos = A[i] - 1;
while(pos >= 0 && pos < n && A[pos] != A[i]) {
swap(A[i], A[pos]);
pos = A[i] - 1;
}
}
思路差不多,但是代码结构不同,在细节上还是很有区别的:
对于第一种:将处理办法放到大的循环中处理,深度迭代计算、位置后移操作看做是同等级操作,所以只要一个while,代码简洁。
对于第二种:两个while处理,实际上位移操作看做主操作,在主操作中深度迭代计算是子操作,逻辑也很清晰,但是代码不够简洁。写完代码之后最好可以转化为第一种
对于第三种:和第二种类似,for循环在这里很适合,但是有些灵活处理的地方需要使用while更好。