Stripe:
Given an array of integers, find the first missing positive integer in linear time and constant space. In other words, find the lowest positive integer that does not exist in the array. The array can contain duplicates and negative numbers as well.
For example, the input [3, 4, -1, 1], should give 2. The input [1, 2, 0] should give 3.
You can modify the input array in-place.
题目分析:
这题的目的是非常清晰的,即在一串数字当中寻找从第一个缺失的正数。要求是线性的时间和常量的空间复杂度。同时,数字序列中还会包含负数和0.
其实两个关于时间或者空间的硬性要求只要去掉其中一个,都是好处理的。如果不需要线性的时间,排序足够解决问题了,如果不需要常量级空间复杂度,那么也可以使用一个哈希表来存储已经出现的正数。
同时满足两者的条件,就必须要从最后一个提示入手,modify the input array in-place. 也就是说,我们是可以将数组进行一定程度的修改。
算法想要达到最高的效率,就必须要搞清楚输入数据的具体模式,并针对这种具体的模式做最合适的处理。
数学表达:
即存在一个序列, , 其中有意义的序列是
,其它的数都是无意义数。如果存在某种方法,可以使得输入数据变为该有意义序列,那么就可以容易得出k的值。由于序列的特征如上,我们可以通过数组的下标来建立这样的有序列。即数组的下标为0的空间存1,下标为1的存2,等等以此类推。
算法设计:
可以设计这样的算法:
遍历整个数组,若该元素的值,我们假定是e 处于1到n之间,那么将它和位于下标e-1位置的元素互换。同时,判断互换的元素值是否满足条件,若满足条件就必须要互换。然后继续判断下一个元素。
最终在数组的头部,就会出现一个有意义序列,通过对该序列的判断可以得出正确的值。
实现:
#include <iostream>
#include <set>
#include <vector>
#include <algorithm>
int findFirstMissingNumber(std::vector<int> &data)
{
std::for_each(data.begin(), data.end(), [&](int &val) {
if (val > 0 && val <= data.size())
{
std::swap(val, data[val - 1]);
if (val > 0 && val <= data.size())
{
std::swap(val, data[val - 1]);
}
}
});
std::for_each(data.begin(), data.end(), [](int val) {
std::cout << val << " ";
});
std::cout << std::endl;
int index = 1;
auto result = std::find_if(data.begin(), data.end(), [&index](int val) {
if (val != index)
{
std::cout << "missing val " << index << std::endl;
return true;
}
else
{
index++;
return false;
}
});
if (result == data.end())
{
std::cout << "no missing val " << data.size() + 1 << std::endl;
}
}
int main()
{
std::vector<std::vector<int>> datas = {
{1, 4, 2, 0},
{2, 3, 9, -1},
{2, 3, 9, 1},
{1, 2, 3, 4}
};
std::for_each(datas.begin(), datas.end(), [](auto &data) { findFirstMissingNumber(data); });
}
$ ./a.exe
1 2 0 4
missing val 3
9 2 3 -1
missing val 1
1 2 3 9
missing val 4
1 2 3 4
no missing val 5