一、数组中只出现一次的两个数字
题目描述
面试题56-1:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
思路分析
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
vector<int> v;
// step 1 : 计算两个只出现一次的数的异或值
int tmp = 0;
for (auto num : nums) {
tmp ^= num; // 任何数和零异或都等于其本身
}
// step 2 : 找到tmp中任意一个为1的位
unsigned int flag = 1;
while ((tmp & flag) == 0) { // 初始值:tmp最后一位为1
flag = flag << 1;
}
// step3: 按照flag分组
int res1 = 0;
int res2 = 0;
for (auto num : nums) {
if (num & flag) {
res1 ^= num;
} else {
res2 ^= num;
}
}
return vector<int> {res1, res2}; // 注意这种写法
}
};
注意:
- == 的优先级比&高
- return vector的写法
二、数组中唯一只出现一次的数字
题目描述
面试题56-2:在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。
思路分析
(1)最优解法,时间复杂度o(n),空间复杂度o(1)
我们想一下如果一个数字出现三次,那么他的二进制位表示的每一位(0或1)也出现了三次.如果把所有出现三次的数字的二进制表示的每一位都分别加起来,那么每一位的和都能被3整除
我们把所有数字的二进制位的每一位加起来.若果某一位的和能被3整除,那么那个只出现一次的数字二进制表示中对应的那一位为0,否则为1
步骤:
统计所有数字二进制位的和
判断每一位的和能否被3整除,求解最后结果
时间复杂度O(n),空间复杂度O(1)(常数空间))
//位运算,统计二进制每一位1出现的次数,每一位%3后结果就是这个数
class Solution {
public:
int singleNumber(vector<int>& nums) {
// 使用常数量空间,存储每一位1的个数
int bits[32] = {0};
//从数组低位到高位存储相应位1的次数
unsigned int flag = 1; //判断当前位是否为1,lecoode中当flag为int时,无法通过测试
for(int i=0; i<32; i++){
for(int j=0; j<nums.size();j++){
// 判断语句很重要,因为&的结果不一定为1,0100
if(nums[j] & flag)
bits[i] = bits[i]+1;
}
flag = flag<<1;
}
// 从高位到低位读取
int result = 0;
for(int i=31; i>=0; i--){
result = (result<<1); //和下面的一个语句不可以交换顺序
result += (bits[i] % 3); //bits[i] % 3 要么为0要么为1
}
return result;
}
};
- 对unsigned int进行移位操作时,最高位不会有任何特殊性。
- 对int进行移位操作时,必须考虑最高位,向右移位操作相当于 (有符号数值)/2。
20240420
class Solution {
public:
// 统计所有数字的各二进制位中 1的出现次数,并对3求余,结果则为只出现一次的数字
int singleNumber(vector<int>& nums) {
// step 1 :求所有数各二进制位的和
vector<int> bits(32, 0);
for (auto num : nums) {
int i = 0;
unsigned int mask = 1;
for (; i < 32; i++) {
if ((num & mask) == mask) {
bits[i]++;
}
mask = mask << 1;
}
}verse(bits.begin(), bits.end()); // 将二进制位正常顺序布置
// step 2 : 各位对3求余,结果为只出现一次的数字
unsigned int res = 0;
for (auto bit : bits) {
res = res << 1;
res |= bit % 3; // 要么等于0,要么等于1
}
return res;
}
};
(2)哈希表解法,时间和空间复杂度均为o(n)
首先遍历一次数组,将每个数字出现的次数存储到哈希表中
查找哈希表中仅出现一次的数字
时间复杂度O(n),空间复杂度O(n)
class Solution{
public:
int singleNumber(vector<int>& nums){
int length = nums.size();
//if(!length) return 0;
map<int, int> hash;
for(int i = 0; i < length; ++i)
++hash[nums[i]];
for(int i = 0; i < length; ++i)
if(hash[nums[i]] == 1)
return nums[i];
return -1; //没有出现一次的,或者输入的空数组
}
};
class Solution {
public:
int singleNumber(vector<int>& nums) {
unordered_map<int, int> mp;
for (auto num : nums) {
++mp[num];
}
unordered_map<int, int>::iterator iter = mp.begin();
for (; iter != mp.end(); iter++) {
if (iter->second == 1) {
break;
}
}
return iter->first;
}
};