LeetCode刷题之路-每日一题-137. 只出现一次的数字 II

题目描述


给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。

示例 1:

输入:nums = [2,2,3,2]
输出:3

提示:
1 <= nums.length <= 3 * 104
-231 <= nums[i] <= 231 - 1
nums 中,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次


解题思路

今天先放动态规划一码!做做《每日一题》
一开始,完全没有思路。休息之后再战,想的是“”除某个元素仅出现 一次 外,其余每个元素都恰出现 三次”这句话肯定富含深意,打算从这里入手。因为之前有题目是通过存储a-z共26个字母来解析存储字符串的分布特征的,所以直接想到,能不能把出现的数字作为下标。下个时刻就否决了,因为数字太大了,这得浪费多少空间。然后想,怎么样能够用暴力破解?通过二维数组来记录每个数字出现的次数,但发现也不好实现。
再过了段时间,我看到下方的进阶要求,于是想,利用额外空间?哦,HashMap可以!每个key就是num[i],value就是出现的次数。于是

public int singleNumber(int[] nums) {
        // 本题思前想后,也只能在题目的进阶那里得到灵感,用hashMap
        int size = nums.length / 3  + 1;
        Map<Integer, Integer> numMap = new HashMap<>(size);

        // 统计每个数字出现的次数
        for (int i=0; i<nums.length;i++) {
            numMap.put(nums[i], numMap.getOrDefault(nums[i], 0) + 1);
        }

        // 找到出现次数为1的
        for (Map.Entry<Integer, Integer> entry: numMap.entrySet()) {
           if (entry.getValue() == 1) {
               return entry.getKey();
           }
        }

        return 0;
    }

但是,是在想不到还是什么其他的更好的方式。看了一眼官方解答,不服不行。。。甚至,到最后面的电路设计解题思路,都直接看不懂,那个根据真值表设计电路的表达式。。。慢慢来吧。第二种解法倒是看懂了。

进阶方案一

每个数字都是int能够表示的,那么就有32bit,所以只要将每个数字的每一位单独加和,然后对3求余。再将余数通过或运算组合成新的32bit,那么就是所求答案。

进阶方案二

这个有点复杂,在方案一中通过整数的每个位置上的数字来解题,那么是否存在位运算可以达到同样的目的呢?
由于1位二进制,无法表示题目中数字出现3次——3种状态,于是想到用2位。00表示出现1次,01表示出现2次,10表示出现了3次。那么对于一个数字而言,必然是00->01->10依次出现,

黑盒中存储了两个整数 aa 和 bb,且会有三种情况:

a 的第 i 位为 0 且 b 的第 i位为 0,表示 0(可以理解为对3求余);
a 的第 i 位为 0 且 b 的第 i 位为 1,表示 1(可以理解为对3求余);
a 的第 i 位为 1 且 b 的第 i 位为 0,表示 2(可以理解为对3求余)。

如果我们用这种状态表示一个数字的二进制位Xi的出现情况,假设有Ai和Bi,则有如下表

AiBiXi新AiBi
00000
00101
01001
01110
10010
10100

可能有些同学还看不懂,这里的意思是,我有2个数字,一个是A,一个是B。还有另外一个数字X,这个X就是我们题目数组中的一个元素。而i表示的是二进制位上的第i位。

而关系表达式 :
Ai=Ai’BiXi + AiBi’Xi’
意思是 Ai’&Bi&Xi 或 Ai&Bi’&Xi’

最后,我们求的是只出现一次的数字,对应会我们的状态(可以理解为对3求余)切换 00(0)-01(1)-10(2),那么就是Bi,所以最后返回B。

今天先到这吧,有点烧脑,不然晚上太兴奋会睡不着的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值