描述 Description
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?
分析 Analysis
本题的意思是,从1到n的整数,其中某个数丢失了,替代它的是0。要我们从0到n之间取出n个不同的数,找出漏掉的那个。
方法1
我们可以用公式计算出从1到n的和,减去实际数组的总和,差值就是那个丢失的数。注意实现的时候,遍历时需要同时记录最大值n(或者在c++等等输入的vector数据中直接通过nums.size()计算出来),积累和,以及是否有0(积累和为n*(n-1)/2,既可能是0漏掉也可能是n+1漏掉。不过实现时候可以稍微使用一点技巧。
方法2(推荐)
类似"single number"利用异或位运算。首先将0到n这些数进行异或运算,然后对输入的数组进行异或运算,最后将两个结果进行异或运算,结果便是漏掉的数字,因为其他数字在两个数组中都是成对出现的,异或运算会得到0。
Note: 从CPU指令所耗费的时钟周期来看,比加法更高效率的运算是异或(XOR)运算。所以其效率应该比方法1好。
方法3
二分查找。首先把数组排序,设中间元素为nums[mid],如果nums[mid]的值大于其下标,说明丢失的数字在左边,反之则在右边。时间复杂度O(nlogn),比前面两个方法慢,但是如果题目给的数组是事先排好序的,那么复杂度就是O(log n),所以这个方法只是用于题目说明是有序时才比XOR更有效。
代码 Code
方法1
int miss = 0, i = 0;
for (int num : nums)
miss += ++i - num;
return miss;
或者
int missingNumber(vector<int>& nums) {
long n = nums.size();
return n * (n+1) / 2 - accumulate(begin(nums), end(nums), 0);
}
方法2
class Solution {
public:
int missingNumber(vector<int>& nums) {
int result = nums.size();
int i=0;
for(int num:nums){
result ^= num;
result ^= i;
i++;
}
return result;
}
};
方法3(java)
public int missingNumber(int[] nums) { //binary search
Arrays.sort(nums);
int left = 0, right = nums.length, mid= (left + right)/2;
while(left<right){
mid = (left + right)/2;
if(nums[mid]>mid) right = mid;
else left = mid+1;
}
return left;
}