剑指offer面试题56题目二-数组中唯一只出现一次的数字

这道剑指offer面试题要求在数组中找出唯一出现一次的数字,其他元素出现三次。通过位运算和HashMap解析问题,由于异或运算不适用,分析二进制每位的和能被3整除的特性来解题。
摘要由CSDN通过智能技术生成

一.题目描述

在一个数组 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

二.题目解析

1.hashmap

public int singleNumber(int[] nums) {
        /*hashmap法,时间复杂度O(n),空间复杂度O(n)
        * */
        int res = -1;
        if(nums == null || nums.length == 0){
            return res;
        }
        Map<Integer,Integer> map = new HashMap<>();
        for (int cur:
             nums) {
            map.put(cur,map.getOrDefault(cur,0) + 1);
        }
        for (Integer i:
                map.keySet()) {
            Integer val = map.get(i);
            if(val == 1){
                res = i;
                break;
            }
        }
        return res;
    }

在这里插入图片描述
2.位运算


数组中只出现一次的两个数字

不同,异或运算不能解决这个问题

上述思路不能解决这里的问题,因为三个相同的数字的异或结果还是该数字。尽管我们这里不能应用异或运算,我们还是可以沿用位运算的思路。
如果一个数字出现三次,那么它的二进制表示的每一位(0或者1)也出现三次。如果把所有出现三次的数字的二进制表示的每一位都分别加起来,那么每一位的和都能被3整除。如果某一位的和能被3整除,那么那个只出现一次的数字二进制表示中对应的那一位是0;否则就是1;

public int singleNumber2(int[] nums) {
        /*位运算,时间复杂度O(n),空间复杂度O(1)
        * */
        int res = -1;
        if(nums == null || nums.length == 0){
            return res;
        }
        //java int类型有32位
        int[] count = new int[32];
        for (int i = 0; i < nums.length; i++) {
            //每计算一个数需要重新初始化
            int mask = 1;
            for (int j = 0; j < 32; j++) {
                //说明nums[i]的第J位值是1
                if((nums[i] & mask) != 0){
                    count[j]++;

                }
                //mask不断左移直到nums[i]的每一位都被统计过
                mask <<= 1;
            }
        }

        //还原各位值为10进制表示
        res = 0;
//        int bitValue = 1;
//以最高位为例,需要左移31次
//i = 0,0次-》i=1,1次-》....i=31,31次
        for (int i = 0; i < count.length; i++) {
            //顺序不能颠倒,否则最后一步会多左移一次
            res <<= 1;
            res += count[31-i] % 3;
        }
        return res;
    }

在这里插入图片描述

总结:数组中一个数字出现一次,其他数字出现奇数次问题可用此方法解决(如果是偶数次,直接用异或运算解决)。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值