给一个未排序的整数序列:找出第一个缺失的正整数。Given [1,2,0]
return 3
, and [3,4,-1,1]
return 2
.
分析:我们可以忽略到那些<=0 数。
这道题如果是不重复的序列的话,也可以用位操作进行计算。
要注意现在是有重复的。
为了找出缺失的,我们先将每个元素都放到一个属于他们的位置上去。放完以后,第一次出现元素的值和所在位置不对应,就可以找到缺失的值。
如何定义:属于某个元素的位置?
假设某个元素为5, 那么它就该被放到index = 4的位置上去,即需要保证 nums[i] = i + 1
所以,对于某一个可能要交换的nums[index],
如果这个 nums[index] > 0 表示是我们想要的正整数。
同时要满足 nums[index] < length 这是因为:>= 了就没法交换,同时,这个nums[index]一定不会是第一个缺失的值。
接下来判断 nums[ nums[index] - 1] == nums[index] 该位置上的值是不是符合要求的,如果不符合,进行交换。
一轮下来,正整数们都放在整理好的位置上了。
最后,浏览数组,如果 nums[index] - 1 != index ,返回 index + 1即可。
代码:
复杂度:
时间复杂度:O(n)
空间复杂度:O(1)
public int firstMissingPositive(int[] nums) {
return firstMissingPositiveByExchange(nums);
}
public int firstMissingPositiveByExchange(int[] nums) {
int i = 0;
while (i < nums.length) {
if (nums[i] > 0 && nums[i] <= nums.length && nums[nums[i] - 1] != nums[i]) {
swap(nums, i, nums[i] - 1);
} else {
i++;
}
}
for (i = 0; i < nums.length; i++) {
if (nums[i] != i + 1) {
return i + 1;
}
}
return nums.length + 1;
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
其他解法:基于hash的解法非常直观,缺点是空间复杂度为O (n)
private int firstMissingPositiveByHash(int[] nums) {
Map<Integer, Boolean> map = new HashMap<Integer, Boolean>();
int minimum = Integer.MAX_VALUE;
for (int i = 0; i < nums.length; i++) {
if (nums[i] > 0) {
map.put(nums[i], true);
minimum = Math.min(minimum, nums[i]);
}
}
if (minimum == Integer.MAX_VALUE || minimum != 1)
return 1;
while (map.containsKey(minimum)) {
minimum++;
}
return minimum;
}