题意大概是给你一个无序数组,希望你找出排序过后,数组从小到大数,第一个没有找到的正数。
例如,nums = [1,2,0],答案应该是3。
因为有时间O(n) 和 空间常数级别的要求,所以像是HashMap、Set、排序之类的操作都不行。O(n)的时间复杂度只能支撑的起遍历数组(或者二分)。
空间常数级别的要求又限制了不能随便根据数组大小开数据结构,所以最多只能是定义变量或者原地修改。
如果时间复杂度允许的话,最简单的方法是排序过后,遍历第一个 位置 i 上的值 不等于 i + 1 那个数就是答案。想了一下,快排的时间复杂度在于不断的折半排序,每一次折半的数组都不是一个有序数组。但如果说,这个数组所有的数组一下就能找到相应的位置的话,排序时间复杂度就下降了。
所以采用递归的方法手动进行排序,将时间复杂度降到O(n),即每一个位置都只排序一次。
排序过程中,如果当前位置 location 上的值并不是 location + 1 说明需要排序,那 nums[location]上的值理论上应该在数组位置的 nums[location] - 1 这个位置上,那么就把nums[location] 上的值交换过去,这个位置就算排好序了,接下来只要再对交换位置上的数在排序,就能得到在特定条件下,O(n)时间复杂度就能排好序的一个数组。
最后,再遍历一遍数组,找第一个不满足条件数的,就是答案。
public int firstMissingPositive(int[] nums) {
for(int i = 0; i < nums.length; i++) {
// 位置正确
if(nums[i] == i + 1) {
continue;
}
// 位置不正确 不断交换
exchange(i, nums[i], nums);
}
for(int i = 0; i < nums.length; i++) {
if(nums[i] != i + 1) {
return i + 1;
}
}
return nums.length + 1;
}
public static void exchange(int initLocation, int val, int[] nums) {
// val 应该存在的位置 location
int location = val - 1;
if(location < 0 || location >= nums.length) {
// 数组越界 不换
return;
}
// tmp val 应该存在的位置 上的值
int tmp = nums[location];
if(tmp <= 0 || tmp > nums.length) {
nums[location] = val;
nums[initLocation] = tmp;
}
if(tmp == location + 1) {
return;
} else {
nums[location] = val;
exchange(initLocation, tmp, nums);
}
}