来源:力扣(LeetCode)
链接:面试题 17.04. 消失的数字
数组nums包含从0到n的所有整数,但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在O(n)时间内完成吗?
注意:本题相对书上原题稍作改动
输入:[3,0,1]
输出:2
输入:[9,6,4,2,3,5,7,0,1]
输出:8
首先了解题目大意:0 — n 中少了一个数字,让我们求出
我现在所能想到的,有三种方法:
接下来唠叨一下方法二与方法三:
思想与相同,通过构造一个假想的完整的 0 — n ,并对其进行二分查找,比如二分查找的中值为4,那么我们在原数组中找小于等于4的个数,如果不含缺失数的话,应该能找到(0, 1, 2, 3, 4)五个数,但如果找到的数小于等于4个,则说明0—4中含有缺失数,则right = mid, 反之,left = mid + 1;
对这种寻找思想感兴趣的话,还可以看这篇文章用二分法解决【寻找重复数】问题
class Solution {
public int missingNumber(int[] nums) {
//二分查找
Arrays.sort(nums);
int len = nums.length;
if(len == 1){
return nums[0] == 0 ? 1 : 0;//特殊情况,当n == 1 的时候,应包含[0, 1]
}
int left = 0, right = len;//左指针,右指针
while(left < right){//循环条件
int mid = left + (right - left) / 2;//中值
int cnt = 0;//计数
for(int num :nums){
if(num <= mid){//原数组中小于等于mid的个数(正常应该有 mid+1 个)
cnt += 1;
}
}
if(cnt <= mid){//如果不到 mid+1 个,即 <= mid
right = mid;//则 0——mid 中有缺失
}else{//反之
left = mid + 1;// mid+1 —— len 有缺失
}
}
return left;//返回left或right(由于循环条件此时left == right)
}
}
这道题目如何用位运算解决呢,当我们看到这道题目的时候,发现他与只出现一次的数字(位运算java)很相似,不同的是,这道题目中有一个数出现的次数是0次,如果让每个数出现的次数都加1,那么两道题好像就一样了。
同样的,我们使用异或的特点:
相同数异或 结果为0
不同数异或 结果为1
一个数与0异或 结果为其本身。
class Solution {
public int missingNumber(int[] nums) {
//位运算
int len = nums.length;//数组中应含有 0——len 即 len+1 个数,少一个数,则只有 len 个数
int m = 0, res = 0;
for(int num : nums){//循环 len 次,0——len-1 个数
res ^= num ^ m;
m += 1;//用m来表示不缺失的 0——len-1 的 len 个数
}
return res ^ len;//记得带上第 len 个数
}
}