1.题目
给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。
进阶:
- 你能否实现线性时间复杂度、仅使用额外常数空间的算法解决此问题?
示例:
输入:nums = [3,0,1]输出:2解释:n = 3,因为有 3 个数字,所以所有的数字都在范围 [0,3] 内。2 是丢失的数字,因为它没有出现在 nums 中。输入:nums = [0,1]输出:2解释:n = 2,因为有 2 个数字,所以所有的数字都在范围 [0,2] 内。2 是丢失的数字,因为它没有出现在 nums 中。输入:nums = [9,6,4,2,3,5,7,0,1]输出:8解释:n = 9,因为有 9 个数字,所以所有的数字都在范围 [0,9] 内。8 是丢失的数字,因为它没有出现在 nums 中。输入:nums = [0]输出:1解释:n = 1,因为有 1 个数字,所以所有的数字都在范围 [0,1] 内。1 是丢失的数字,因为它没有出现在 nums 中。
提示:
n == nums.length1 <= n <= 10^40 <= nums[i] <= nnums中的所有数字都 独一无二
2.思路
如果数组是有序的,我们很容易就可以求出丢失的那个数
public int missingNumber(int[] nums) {Arrays.sort(nums);// 判断 n 是否出现在末位if (nums[nums.length-1] != nums.length) {return nums.length;}// 判断 0 是否出现在首位else if (nums[0] != 0) {return 0;}// 此时缺失的数字一定在 (0, n) 中for (int i = 1; i < nums.length; i++) {int expectedNum = nums[i-1] + 1;if (nums[i] != expectedNum) {return expectedNum;}}// 未缺失任何数字(保证函数有返回值)return -1;}
哈希表
public int missingNumber(int[] nums) {Set<Integer> numSet = new HashSet<Integer>();for (int num : nums) numSet.add(num);int expectedNumCount = nums.length + 1;for (int number = 0; number < expectedNumCount; number++) {if (!numSet.contains(number)) {return number;}}return -1;}
位运算
可以将结果的初始值设为 n,再对数组中的每一个数以及它的下标进行一个异或运算,即:
| 下标 | 0 | 1 | 2 | 3 |
|---|---|---|---|---|
| 数字 | 0 | 1 | 3 | 4 |
missing
=4∧(0∧0)∧(1∧1)∧(2∧3)∧(3∧4)
=(4∧4)∧(0∧0)∧(1∧1)∧(3∧3)∧2
=0∧0∧0∧0∧2
=2
public int missingNumber(int[] nums) {int missing = nums.length;for (int i = 0; i < nums.length; i++) {missing ^= i ^ nums[i];}return missing;}
高斯求和公式
public int missingNumber(int[] nums) {int expectedSum = nums.length*(nums.length + 1)/2;int actualSum = 0;for (int num : nums) actualSum += num;return expectedSum - actualSum;}
