题目:
给定一个包含 [0, n]
中 n
个数的数组 nums
,找出 [0, n]
这个范围内没有出现在数组中的那个数。
解法一(排序):
将数组排序后,可根据数组中每个下标处元素是否和下标相等,找到丢失的数字。由于数组的长度是n,因此下标范围是[0, n-1],假设缺失的数组是k,当0≤k<n时,对任意0≤i<k,都有nums[i]=i,由于k缺失,因此nums[k]=k+1,k是第一个满足下标和元素不相等的下标;当k=n时,0到n-1都没有缺失,因此对任意0≤i<n,都有nums[i]=i。
根据上述两种情况,可以得到如下方法得到丢失的数字:
1、从左到右遍历数组 nums,如果存在 0≤i<n 使得 nums[i]=i,则缺失的数字是满足 nums[i]=i 的最小的 i;
2、如果对任意 0≤i<n,都有 nums[i]=i,则缺失的数字是 n。如下为所示代码:
class Solution {
public:
int missingNumber(vector<int>& nums) {
//对容器vector数组nums进行排序sort()
sort(nums.begin(),nums.end());
int n = nums.size();
//一次遍历数组,数组下标不等于数组值时返回丢失数字,若遍历完仍没有查找到时,即为数字n(末端)
for (int i = 0; i < n; i++) {
if (nums[i] != i) {
return i;
}
}
return n;
}
};
特别注意:sort
函数是用于对vector容器中的元素进行排序的一个算法,通常定义在 <algorithm>
头文件中。它可以对一个范围内的元素进行排序,默认按照升序排序,但也可以通过自定义比较函数来实现降序或其他排序方式。例如sort(nums.begin(),nums.end()) 按升序排列。
void sort(RandomIt first, RandomIt last, Compare comp);
first 和 last:指定要排序的范围,first
是范围的起始迭代器,last
是范围的末尾迭代器
comp:是一个二元谓词函数,接受两个元素作为参数并返回布尔值。comp
返回 true
时,表示第一个元素应该排在第二个元素之前(升序排序),返回 false
则反之。如果不提供该参数,sort
会默认按照升序排列。
解法二(哈希表):
首先遍历数组 nums,将数组中的每个元素加入哈希集合,然后依次检查从 0 到 n 的每个整数是否在哈希集合中,不在哈希集合中的数字即为丢失的数字。由于哈希集合的每次添加元素和查找元素的时间复杂度都是 O(1),因此总时间复杂度是 O(n)。如下为笔者代码:
class Solution {
public:
int missingNumber(vector<int>& nums) {
int n = nums.size();
unordered_map<int,int> hashTable1;
for(int i=0; i<n; i++){
hashTable1[nums[i]]=nums[i];
}
for(int i=0; i<n+1;i++){
if(hashTable1.count(i)>0){
continue;
}
else{
return i;
}
}
return 0;
}
};
时间复杂度为O(n),其中n是数组nums的长度。遍历数组nums将元素加入哈希表的时间,以及遍历从0到n每个整数是否在哈希表中的时间复杂度均是O(n)。空间复杂度是O(n),其中n是数组nums的长度。哈希表中需要存储n个整数
解法三(位运算):
数组nums中有n个数,在这n个数后面添加从0到n的每个整数,则添加了n+1个整数,共有2n+1个整数,在2n+1个整数中,丢失的数字只在后面n+1个整数中出现一次,其余的数字在前面n个整数中(即数组中)和后面n+1个整数中各出现一次,即其余的数字都出现了两次。
根据出现的次数的奇偶性,可以使用按位异或运算得到丢失的数字。按位异或运算满足交换律和结合律,对任意整数x都满足x⊕x=0 和 x⊕0=x。由于上述2n+1个整数中,丢失的数字出现了一次,其余的数字都出现了两次,因此对上述2n+1个整数进行按位异或运算,结果即为丢失的数字,实现代码如下所示:
class Solution {
public:
int missingNumber(vector<int>& nums) {
int res = 0;
int n = nums.size();
//先将nums数字进行位异或运算
for (int i = 0; i < n; i++) {
res ^= nums[i];
}
//再将新添加的n+1个整数进行位异或运算
for (int i = 0; i <= n; i++) {
res ^= i;
}
return res;
}
};
位运算实现的代码的时间复杂度为O(n),其中n是数组nums的长度,需要对2n+1个数字计算按位异或的结果,空间复杂度为O(1):在运算过程中,没有进入新的数据结构对数据进行存储,位运算不需要存储空间复杂度。