41. First Missing Positive
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.
题目内容:
给定一个无序的整形数组nums,找出数组中第一个缺失的正整数。
例如给出[1, 2, 0]这个数组,数组中存在连续的正整数1,2所以缺失的第一个正整数是3。
对于数组[3, 4, -1, 1],包含正整数1,3,4,缺少了1后面的2。
解题思路:
因为题目要求是找出第一个不连续的正整数,所以很容易想到,对于非正整数我们可以直接忽略掉。整个解题步骤可以分为3个步骤:
(1) 找出数组中非正整数的数量
找出数组中的非正整数可以简单地通过一个循环来实现,非正整数的数量作为startIndex
(2) 通过元素之间的换位将数组分成两大部分,非正整数和整数,如下图:
这个数组之间的换位是为了使得当num[i]为正整数的时候,nums[i] == i - startIndex + 1,实际上就是例如
当1存在数组里,nums[startIndex + 0] == 1;
当2存在数组里,nums[startIndex + 1] == 2;
……
当正整数n存在数组里,nums[startIndex + n - 1] == n;
也就是说,我们要从头开始遍历数组,遍历到一个正整数的时候,就要将这个正整数换位到相应的位置,但是也不是全部正整数都需要换位置,总的来说,对于数组nums的第i元素,同时满足以下4个条件的时候才需要换位置:- 是一个正整数。
- num[i]的值与其下标不符合,即nums[i] != i - startIndex + 1
- num[i]应在的位置下标不超过了数组的长度,即startIndex + nums[i] - 1 < nums.size()。因为对于总长度为nums.size()的数组,存在startIndex个非正整数,所以最大连续的正整数也就是nums.size() - startIndex。所以这种如果num[i]应在的位置下表已经超过了数组的长度,可以忽略这个数。
- num[i]应在的位置与num[i]相同。题目没有说这个数组的元素是唯一的,所以可能存在相同的元素,也就是说当这个元素满足了前3个条件,但是如果要交换的位置的元素已经跟当前元素相同,那也是不需要交换的。
这里还有一个需要注意的,就是交换后的元素也可能满足上述需要交换的4个条件,以题目给出的[3, 4, -1, 1]为例,如下图:
因为数组中只存在一个非正整数,所以startIndex为1。从第一个位置开始遍历,发现nums[0]需要和nums[3]交换,交换后,发现新的nums[0]需要与nums[1]交换,现在新的nums[0]为4,按理来说应该与nums[4]交换,但是很明显这已经超过了数组的长度,所以可以忽略,进入下一个元素的处理,并且可以发现后面的元素都不需要换位了。
(3) 从startIndex开始遍历数组,找到第一个数组下标与该下标的值不匹配的位置,既是第一个不连续的正整数。
经过上一步的处理后,就可以再通过一次遍历来查找第一个缺失的正整数了。因为可能的第一个正整数是1,经过上述的处理后,如果1存在数组里,1应该会放在startIndex的位置,所以只需要从startIndex开始遍历数组。当找到第一个下标与该下标的元素值不对应的位置或者已经遍历到数组的结尾了,则可以认为(上一个位置的值+1)就是第一个缺失的正整数。但是当第一个正整数1就不存在的话,如果我们把(上一个位置的值+1)作为第一个缺失的正整数是不合理的,因为startIndex前面位置的元素是没有意义的。所以当startIndex位置的元素已经不匹配,那么直接返回1就可以了。
代码:
#include <vector>
#include <iostream>
using namespace std;
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
if (nums.size() == 0) {
return 1;
}
int startIndex = 0;
int nums_index = 0;
vector<int>::iterator it = nums.begin();
while (it != nums.end()) {
if (*it <= 0) {
startIndex++;
}
it++;
}
while (nums_index < nums.size()) {
if (nums[nums_index] > 0 && nums_index != startIndex + nums[nums_index] - 1
&& startIndex + nums[nums_index] - 1 < nums.size() && nums[startIndex + nums[nums_index] - 1] != nums[nums_index]) {
swap(nums, nums_index, startIndex + nums[nums_index] - 1);
}
else {
nums_index++;
}
}
it = nums.begin() + startIndex;
while (it != nums.end()) {
if (*it != (it - nums.begin()) - startIndex + 1) {
if (it == nums.begin() + startIndex) {
return 1;
}
return (*(it - 1)) + 1;
}
it++;
}
return (*(it - 1)) + 1;
}
void swap(vector<int>& nums, int x, int y) {
int temp = nums[x];
nums[x] = nums[y];
nums[y] = temp;
}
};
int main(int argc, char** argv) {
int iarray[] = {3, 4, -1, 1};
int count = sizeof(iarray) / sizeof(int);
vector<int> v(iarray, iarray+count);
Solution sln;
cout << sln.firstMissingPositive(v) << endl;
return 0;
}