剑指Offer_#56-II_ 数组中数字出现的次数II

剑指Offer_#56-II_ 数组中数字出现的次数II

Contents

题目

在一个数组 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次的数字,每个二进制位也出现3次;多组出现3次的数字叠加,每个二进制位出现次数是3的倍数。
  • 再考虑只出现一次的数字,即我们的目标数字。目标数字中,出现1的二进制位会增加到之前的统计次数中,使得这个位置出现1的总次数不再是3的倍数。

算法流程

  1. 遍历数组,对于每个元素,循环右移位,通过掩码1获取到二进制表示中每一位1出现的次数,保存到一个辅助数组中,索引表示第几位,元素表示出现的次数。
  2. 遍历刚才的辅助数组,看每个元素对3取余的结果
    • 若为0说明这一位出现了3的整数倍次,必然没有在目标数字中出现过,所以不计算
    • 若不为0,说明这位数字出现在目标数中,res加上digit,也就是当前二进制位的数量级(2n

解答

class Solution {
    public int singleNumber(int[] nums) {
        int res = 0;
        //二进制中每一位数字的数量级
        int digit = 1;
        //统计二进制表示中每一位出现的总个数
        int[] numTimes = new int[32];
        for(int num:nums){
            for(int i = 0; i <= 31;i++){
                //如果第i位是1,那么help[i]增加1
                numTimes[i] += (num & 1);
                //继续统计下一位
                num >>= 1;
            }
        }
        //遍历help[]数组
        for(int times:numTimes){
            res += digit * (times % 3);
            digit <<= 1;
        }
        return res;
    }
}

复杂度分析

时间复杂度:O(n),两层循环中,第二层循环次数是常数,所以还是O(n)。
空间复杂度:O(1),借助一个辅助数组,其长度是常数。

猜你喜欢

转载自www.cnblogs.com/Howfars/p/13365560.html
今日推荐