题目 缺失的第一个正数
给你一个未排序的整数数组,请你找出其中没有出现的最小的正整数。
示例 1:
输入: [1,2,0]
输出: 3
示例 2:
输入: [3,4,-1,1]
输出: 2
示例 3:
输入: [7,8,9,11,12]
输出: 1
提示:
你的算法的时间复杂度应为O(n),并且只能使用常数级别的额外空间。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/first-missing-positive
思路
是个未排序的数组,那么第一反应当然是先排序再按序寻找正确的答案。但是提示里很快限定了O(n)的时间复杂度,再加上题目是寻找一个正整数,那么答案呼之欲出了,只有采用外部排序的方式才能达到效果。
但是,原本打算用哈希表存储数组结果,然后寻找缺失的正整数。结果要求用常数级别的空间,这意思就是在外部排序的基础上还要优化一下空间复杂度(然后我又不厚道地去瞄了眼官解的思路,这次官解的做法真的够巧妙的)。
这时候可以注意到,如果数列中没有1,那么输出必然是1。后续的2和3也是同理,这样其实可以得出一个结论,那就是长度为N的数组至多能包括1——N。那么可以用数组本身来判断缺失的正整数是多少:
举例说明一下这个方法:
输入: [1,3,2, 5]
我们检查到有一个1,那么就将数组的a[0]置为相反数即-1,然后检查到一个3,那么将数组的a[2]置为相反数,即-2,然后检查到一个-2,绝对值为2,那么将数组的a[1]置为相反数,也就是-3,最后加查到一个5,它比数组长度还大,那么不做操作。
此时数组的样子:
[-1,-3,-2,5]
此时我们依次遍历一下数组,找到第一个不是负数的数,它是数组中的第4个数,那么答案为4.
这样去做的话,只使用了原数组的空间,空间复杂度为1.
当然这里还有个小问题,如果遇到了负值怎么处理呢?之前说了长度为N的数组至多只能表示到N,那么将所有负数和0都置为N+1就不会影响这个算法的答案啦。
代码实现
依旧是直接放代码的实现:
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
int length = nums.size();
int answer = 1;
if (nums.size() == 0) {
return answer;
}
for (int i = 0; i < length; i++) {
nums[i] <= 0 ? nums[i] = length + 1: nums[i];
}
for (int i = 0; i < length; i++) {
int absolute = abs(nums[i]);
if (absolute <= length) {
nums[absolute - 1] > 0 ? nums[absolute - 1] = 0 - nums[absolute - 1] : nums[i];
}
}
for (int i = 0; i < length; i++) {
if (nums[i] > 0) {
return i + 1;
}
}
return length + 1;
}
};
基本上按着前面说的思路依次实现即可。