数组中数字出现的次数Ⅱ

一、需求

  • 在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次;
  • 请找出那个只出现一次的数字。
示例 1:

输入:nums = [3,4,3,3]
输出:4
示例 2:

输入:nums = [9,1,7,9,7,9,7]
输出:1

二、哈希表

2.1  思路分析

  1. 遍历数组,利用哈希表存储数组中每个元素以及各自出现的次数,最后返回次数为1的元素即可;

2.2  代码实现

class Solution {
    public int singleNumber(int[] nums) {
        Map<Integer,Integer> hm = new HashMap<>();
        for(int i = 0; i < nums.length; i++) {
            if(hm.containsKey(nums[i])) {
                hm.put(nums[i], hm.get(nums[i])+1);
            } else {
                hm.put(nums[i], 1);
            }
        }
        for(Integer key : hm.keySet()) {
            if(hm.get(key) == 1) return key;
        }
        return -1;
    }
}

2.3  复杂度分析

  • 时间复杂度为O(N);
  • 空间复杂度为O(N),哈希表存储数组元素占用O(N)的空间;

三、位运算法

3.1  思路分析

  1. 题目规定1 <= nums[i] < 2^{31},那么num[i]它的二进制位数最多为 32 位,我们建立一个counts数组来存在数组中所有元素其二进制位(从低位到高位)为1的个数,比如[3,4,3,3],3的二进制为...0011,4的二进制为...0100,那么该数组对应的counts数组中的值是[3,3,1,0,0,0...],即最低位1出现了3次,次低位1出现了3次,次次低位1出现了1次,其余位没有出现1,均为0;
  2. 通过1发现,只要当前counts数组对3取余即可得到[0,0,1,0,0,0...],这就是原数组中只出现1次的那个元素的二进制表示;
  3. 现在要将该二进制还原成原数字,可通过0*2^0+0*2^1+1*2^2+...来计算;

3.2  代码实现 

class Solution {
    public int singleNumber(int[] nums) {
        int[] counts = new int[32];
        for(int num : nums) {
            //将每个数的二进制位累加到counts数组中
            for(int j = 0; j < counts.length; j++) {
                counts[j] += num & 1;
                num = num >> 1;
            }
        }
        //获得不重复数字的二进制位
        for(int i = 0; i < counts.length; i++) {
            counts[i] = counts[i] % 3;
        }
        //将二进制位转换成整数返回
        int res = 0;
        int tmp = 1;//看作2^0
        for(int i = 0; i < counts.length; i++) {
            res += tmp * counts[i];
            tmp <<= 1;
        }
        return res;
    }
}

3.2  代码优化

class Solution {
    public int singleNumber(int[] nums) {
        int[] counts = new int[32];
        for(int num : nums) {
            for(int j = 0; j < counts.length; j++) {
                //当前最低位为1或0,是1就累加当前位1的个数
                counts[j] += num & 1;
                //将次低位移动到最低位
                num >>>= 1;
            }
        }
        //根据二进制位恢复只出现一次的数字
        int tmp = 1;
        int res = 0;
        for(int i = 0; i < counts.length; i++) {
            res += counts[i] % 3 *tmp;
            tmp <<= 1;
        }
        return res;
    }
}

3.3  复杂度分析

  • 时间复杂度为O(N),其中N为数组元素的个数,每个数组元素进行位运算消耗的时间复杂度为O(1),故总体时间复杂度为O(N);
  • 空间复杂度为O(1),数组counts和几个变量占用常数大小的额外空间;

四、学习地址

作者:Krahets

链接:https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-ii-lcof/solution/mian-shi-ti-56-ii-shu-zu-zhong-shu-zi-chu-xian-d-4/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值