First Missing Positive
Solution 1
如果不加限制,这个题其实很好做,但是限制了限行时间和常数空间,那么直接使用排序或者任何传统哈希方法都会违反要求。官方题解给出了一个非常好的原地哈希算法(是的!我又不会做!)。本题存在的一个性质:答案只在[1,N+1][1, N + 1][1,N+1]之间,如果1到NNN之间存在空缺,那么答案就是其中最小的一个;否则,答案就是N+1N + 1N+1,那么就是要想办法找到1到NNN之间缺了哪些数,对于负数和大于NNN的数字是没有考察意义的。本题的限制导致我们需要进行原地哈希,利用现有的数组空间作为哈希桶标记数据,同时尽量不破坏原有数据。
官方题解的方案就非常巧妙,由于答案必然和输入中的负数无关,那就先把这些负数处理掉,然后用符号作为标记的依据:
- 遍历输入,如果当前考察数字为负数,将其置为N+1N + 1N+1(原位哈希,这些数字将不会被处理)
- 再遍历输入,如果当前数字xxx并非负数,那么将对应的x−1x - 1x−1置为绝对值相同的负数(负数在前一步已经被处理,超过NNN的数字直接跳过)
- 最后遍历一遍输入,如果索引iii位置的数字是正数,代表对应位置数字xxx缺失
- 时间复杂度:O(N)O(N)O(N),NNN为输入长度,始终进行线性遍历
- 空间复杂度:O(1)O(1)O(1),原位哈希,不占用额外空间
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
for (auto & num: nums) {
if (num <= 0) {
num = nums.size() + 1;
}
}
for (auto num: nums) {
if (abs(num) <= nums.size()) {
nums[abs(num) - 1] = - abs(nums[abs(num) - 1]);
}
}
// for (auto num: nums) {
// cout << num;
// }
// cout << endl;
int ans = nums.size() + 1;
for (int i = 0; i < nums.size(); ++i) {
if (nums[i] >= 0) {
ans = i + 1;
break;
}
}
return ans;
}
};
Solution 2
Solution 1的Python实现
class Solution:
def firstMissingPositive(self, nums: List[int]) -> int:
for i in range(len(nums)):
if nums[i] <= 0: nums[i] = len(nums) + 1
# print(nums)
for num in nums:
# print(num)
if 0 < abs(num) and abs(num) <= len(nums):
# print("Check", num)
nums[abs(num) - 1] = - abs(nums[abs(num) - 1])
ans = len(nums) + 1
# print(nums)
for i in range(len(nums)):
if nums[i] > 0:
ans = i + 1
break
return ans
本文介绍了一种在常数空间和线性时间内找到数组中最小缺失正整数的算法。通过巧妙地利用输入数组本身作为哈希表,该算法能够高效地解决这一问题,并提供了C++和Python两种实现方式。
1209

被折叠的 条评论
为什么被折叠?



