Medium | 剑指 Offer 56 - II. 数组中数字出现的次数 II | 位运算
剑指 Offer 56 - II. 数组中数字出现的次数 II
在一个数组 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
解题思路
在 Easy | LeetCode 136. 只出现一次的数字 | 位运算 中, 只有一个数字出现一次, 其余出现两次的情况下, 我们直接异或所有值就解决了。
在 Medium | 剑指 Offer 56 - I. 数组中数字出现的次数 | 位运算 中, 我们通过分组, 然后在分组内异或所有值解决了。
因为上述两个题中, 哪些重复出现的数字是出现了两个, 将其异或可以抵消。而此题是重复数字出现了三次, 将其异或的话就是其自身了。所以没办法通过异或的方式解决。
其实解决的办法也比较通俗, 就是使用一个数组来保存其二进制各个位的和。然后对每一位mod 3, 最终数组里的数就是那个只出现了一次的那个数的二进制表示。理解起来也很容易, 因为出现了三次的那些数, 在二进制各个位相加然后各位mod 3的过程, 全部都变成0了。最终剩下的就是那个只出现了一次的二进制位。
public int singleNumber(int[] nums) {
int[] bitSum = new int[32];
int index = 0;
// 从最低位开始遍历所有位, 并求和, 放到每个位在数组的对应位置
for(int i = 31; i >= 0; i--) {
for(int num : nums) {
bitSum[i] += ((num >> index) & 1);
}
index++;
}
int res = 0;
// 最终数组每个数字mod 3的结果就是目标数字的二进制位
// 从左往右扫描, 并叠加计算其十进制的值
for(int i = 0; i < 32; i++) {
res = res << 1;
res += (bitSum[i] % 3);
}
return res;
}