【剑指offer】【位运算】56 - II. 数组中数字出现的次数 II
题目链接:https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-ii-lcof/
思路
关键点
还是从位运算的角度,考虑数字的二进制形式,各二进制位出现的次数都是3的倍数。说明出现了三次;因此,统计所有数字的各二进制位中1出现次数,并对3求余,结果为只出现一次的数字;
逐位统计
时间复杂度:O(32*n)≈ O(n)
空间复杂度:O(1)
class Solution {
public:
int singleNumber(vector<int>& nums) {
vector<int> count(32, 0);
for(auto num : nums)
for(int i = 0; i < 32; i++)
{
//获取二进制数字 num 的最右一位
count[i] += num & 1;
//右移一位
num >>= 1;
}
int res = 0;
for(int i = 0; i < 32; i++)
{
//左移 1 位
res <<= 1;
//将count数组中各二进位的值恢复到数字res上
res |= count[31 - i] % 3;
}
return res;
}
};
位运算 + 状态转移
时间复杂度:O(n)
空间复杂度:O(1)
基本想法,统计每一位出现0还是1
先考虑遍历一个数的每一位的情况:
遇到0,不变;
遇到1, 00 -> 01 -> 10 -> 00 三种状态之间循环
遍历完所有数字后,各二进制位都处于状态 00 和状态 01 (取决于 “只出现一次的数字” 的各二进制位是 11 还是 00 ),而此两状态是由 once 来记录的(此两状态下 twice 恒为 00 ),因此返回 once 即可。
如果,一个数出现了三次,状态是00;如果出现了一次,状态就是01,once上存的就是结果;
class Solution {
public:
int singleNumber(vector<int>& nums) {
int once = 0, twice = 0;
for(auto x : nums)
{
once = once ^ x & ~twice;
twice = twice ^ x & ~once;
}
return once;
}
};
知识的价值不在于占有,而在于使用

浙公网安备 33010602011771号