注:
运算符的运算顺序
指针最优,单目运算优于双目运算。如正负号。
先算术运算,后移位运算,最后位运算。
题目:
在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。
示例 1:
输入:nums = [3,4,3,3]
输出:4
示例 2:
输入:nums = [9,1,7,9,7,9,7]
输出:1
限制:
1 <= nums.length <= 10000
1 <= nums[i] < 2^31
题解:
解题思路:
如下图所示,考虑数字的二进制形式,对于出现三次的数字,各 二进制位 出现的次数都是 3 的倍数。
因此,统计所有数字的各二进制位中 1 的出现次数,并对 3 求余,结果则为只出现一次的数字。
遍历统计
使用 与运算 ,可获取二进制数字num 的最右一位 n1=num&1
配合 无符号右移操作 ,可获取 num 所有位的值:
num=num>>1
建立一个长度为 32 的数组 counts ,通过以上方法可记录所有数字的各二进制位的 1 的出现次数。
将 counts 各元素对 3 求余,则结果为 “只出现一次的数字” 的各二进制位。
利用 左移操作 和 或运算 ,可将 counts 数组中各二进位的值恢复到数字 res 上(循环区间是i∈[0,31] )。
复杂度分析:
时间复杂度 O(N) : 其中 N 位数组 nums 的长度;遍历数组占用 O(N) ,每轮中的常数个位运算操作占用 O(1) 。
空间复杂度 O(1) : 数组 countscounts 长度恒为 32 ,占用常数大小的额外空间。
class Solution {
public:
int singleNumber(vector<int>& nums) {
vector<int> count(32);
for(auto num:nums){
for(int j=0;j<32;j++){
count[j]=count[j]+(num&1);
num=(num>>1);
}
}
int result=0;
for(int i=31;i>=0;i--){
result=(result<<1);
result=(result|(count[i]%3));
}
return result;
}
};