Missing Number
Given an array containing n distinct numbers taken from 0, 1, 2, …, n, find the one that is missing from the array.
For example, Given nums = [0, 1, 3] return 2.
Note: Your algorithm should run in linear runtime complexity. Could you implement it using only constant extra space complexity?
二分搜索法 Binary Search
复杂度
时间 O(NlogN) 空间 O(1)
思路
先将数组排序,然后进行二分搜索。显然,中点的下标和中点的值相同时,说明从起始到中点没有错位,缺失数应该在数组后边。如果不相等,说明前面已经有错位,缺失数在左边。如果缺失数是最后一个的话,那整个数组都没有错位,则要返回最后一个加1。
注意
虽然原题中这个方法并不是最优的,但如果题目中的数组已经排序的了,那二分法就比其他两个方法要好了。
代码
public class Solution {
public int missingNumber(int[] nums) {
Arrays.sort(nums);
int min = 0, max = nums.length - 1;
while(min < max){
int mid = (min + max) / 2;
// 没错位,在右边。有错位,则在左边
if(mid == nums[mid]){
min = mid + 1;
} else {
max = mid - 1;
}
}
// 如果没有错位,则返回最后一个数加1
return nums[min] == min ? min + 1 : min;
}
}
等差数列计算法 Arithmetic Progression
复杂度
时间 O(N) 空间 O(1)
思路
由题意,大小为n的数组里的所有数都是0 – n之间的数,作为等差数列,如果没有缺失的时候它的和是能O(1)计算出来的,所以我们遍历一遍记录最大、最小和数组和,用期望数组和减去实际数组和,就是缺失的整数
注意
缺失0和缺失n的时候要特殊处理,因为他们俩的期望和减去实际和都是0。记录最小值可以用来判断是否缺失0。
代码
public class Solution {
public int missingNumber(int[] nums) {
if(nums.length == 0) return 0;
int max =0, min= nums[0], sum = 0;
for(int i = 0; i < nums.length; i++){
sum += nums[i];
max = Math.max(max, nums[i]);
min = Math.min(min, nums[i]);
}
int correctSum = (max + 0) * (max - 0 + 1) / 2;
return correctSum - sum;
}
}
异或法 Exclusive OR
复杂度
时间 O(N) 空间 O(1)
思路
根据异或的特性,对于一个数,异或自己是0,异或0是自己,所以我们把0-n都异或一遍,再对着给定数组异或一遍,结果就是缺失的数。
代码
public class Solution {
public int missingNumber(int[] nums) {
int res = 0;
for(int i = 0; i <= nums.length; i++){
res ^= i == nums.length ? i : i ^ nums[i];
}
return res;
}
}
First Missing Positive
Given an unsorted integer array, find the first missing positive integer.
For example, Given [1,2,0] return 3, and [3,4,-1,1] return 2.
Your algorithm should run in O(n) time and uses constant space.
映射法
复杂度
时间 O(N) 空间 O(1)
思路
核心思想就是遍历数组时,将每个元素,和以该元素为下标的元素进行置换,比如第一个元素是3,就将它置换到下标为3的地方,而原本下标为3的地方的元素就换到第一个来。如果换来的元素也是在正确的位置就检查下一个元素,否则继续交换,直到:
待交换的两个数是一样的
当前位置的元素没有对应的目的地(比如负数,或者超界元素)
注意
数组是从0开始的,而正数是从1开始的,为了简化映射关系,把数组里所有元素都减了1,最后返回答案时再加1即可。
如果最后还没找到,就说明缺失的是最后一个数n
代码
public class Solution {
public int firstMissingPositive(int[] nums) {
//减1预处理数组,简化映射关系
for(int i = 0; i < nums.length; i++){
nums[i]--;
}
for(int i = 0; i < nums.length;i++){
while(nums[i]!=i && nums[i] >=0 && nums[i]<nums.length && nums[i]!=nums[nums[i]]){
int tmp = nums[i];
nums[i] = nums[nums[i]];
nums[tmp] = tmp;
}
}
//找出第一个不在对应位置的数
for(int i = 0; i < nums.length; i++){
if(nums[i]!=i) return i+1;
}
//都没找到说明是最后一个数
return nums.length+1;
}
}