Loading

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;
    
}
posted @ 2021-01-16 12:37  反身而诚、  阅读(95)  评论(0编辑  收藏  举报