力扣136. 只出现一次的数字 数组中出现两次的数字

只出现一次的数字

题目来自


代码及思路

按位或 | ,有一为一,其他为零。(二进制位中对应运算的两个二进制位,只要有一个为1,其结果就是1)
0011      10进制3
0010      10进制2
0011      10进制3(结果)

按位与 & ,均一为一,其他为零。(对应的二进制位均为1,结果才是1)
0011      10进制3
0010      10进制2
0010      10进制2(结果)

按位异或 ^,不同为一,其他为零。(比如 (1^0) (0^1))
0011      10进制3
0010      10进制2
0001      10进制1(结果)

    /**
     * 这里有一个“定理” :
     *           两个相同的数字进行异或,结果为零。
     *           零和任何数字进行异或,结果为那个任何数字。
     *
     * 拓展推理:
     *           二进制位进行的运算,与,异或,或,与顺序无关。
     *           题目中,只有一个数字只出现一次,其他数字都出现两次。
     *           由于已经知道以二进制位进行的运算和顺序无关。
     *           那么最终必然为: 1 ^ 1 ^ 2 ^ 2 ^ 3 ^ 3 ^ 4 = 4。(举个栗子)
     *
     */
    public int singleNumber(int[] nums) {
        int x = nums[0];
        for( int i = 0 ; i < nums.length ; i ++ ){
            x ^= nums[i];
        }
        return x;
    }

 

数组中出现两次的数字

题目来自

代码及思路

    public int[] singleNumbers(int[] nums) {
        /**
         * 在已经懂上一题的情况下,这一题会变得简单一些...
         * 这题的思路是让这两个不同的数字分组,让它们处在不同的组(其他相同的数字在哪一组无所谓,但是他们一定是成对在一组的),
         * 这样一来不就又变成第一题了吗
         */
        int res = 0;
        /**
         * 得到所有数字的异或结果res
         * 取res上对应的二进制为1,让其转换成十进制div
         * 然后让div与所有的数字进行按位于&,结果为零的为一组
         * 不为零的为另外一组,具体为什么,往后看
         */
        for (int i = 0; i < nums.length; i++) {
            res ^= nums[i];
        }
        int div = 1;
        /**
         * 
         * 官方的解释是找res中二进制位为1的任意一位,让其转变成十进制div
         * 举个栗子 res 0111 div 可以为 1, 2, 4(注意这里是可以随意挑选的,但是挑选的位会影响分组)
         * 
         * 来看下为什么能达到分组的效果(首先如果懂了第一题的话,就知道异或操作,满足“交换律”等等)
         * 
         * 先用一个例子展开
         * 4,4,5,3,2,2,7,7
         * 4         0011
         * 5         0101 目标数
         * 3         0011 目标数
         * 2         0010
         * 7         0111
         * 
         * res       0110 异或结果
         * 
         * ---------------------------------------------------------------------------
         * 5         0101 目标数
         * 3         0011 目标数
         * div       0100   (假设用这个二进制位来进行分组,按位于&结果为零的为一组,否则为另外一组)
         *                  (按位于&,同一位一,其他为零)
         *                  (所以只有和div一样,在对应的位置上,该二进制位为1,结果才会为1)重点<---------
         *                   
         *                     **相同的两个数和div进行按位于&,结果是一样的,它们一定在一组。重点<---------
         *                       (具体在哪一组和div的选择有关系,也和数字有关系,比如上面例子4,7就不在一组)
         *                       
         *                     **目标数和div按位于&,一定在不同的组(因为所有数字的异或结果,其实就是这两个不同数字异或得出的结果,异或,不同为一,其他为零)重点<---------
         * 4         0011
         * 2         0010
         * 7         0111
         * 
         * 用res中的任意一位为1的二进制位,与所有数字进行 按位与& 操作
         * 结果为零的一组,不为零的为另外一组
         * 重点来了,为什么呢??
         */
        while ((div & res) == 0) {
            // 乘以2
            div <<= 1;
        }
        int a = 0, b = 0;
        for (int i = 0; i < nums.length; i++) {
            if ((div & nums[i]) != 0) {
                a ^= nums[i];
            } else {
                b ^= nums[i];
            }
        }
        int []A = {a, b};
        return A;
    }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
leetcode中国 :cloud:LeetCode-Notes:cloud: Thomas学编程! :water_wave:力扣刷题,力扣探索学习,我的LeetCode刷题学习计划:rocket: :water_wave:为了促进刷题学习,我建立了这个仓库促进我刷题 我的Github: 我的LeetCode: 联系我?:clinking_beer_mugs: :closed_mailbox_with_raised_flag:邮箱: :link:博客: 仓库正在建设中…… :thumbs_up:客官,点个赞?:thumbs_up: :star:如果对您有帮助的话,请点一个star再走? :eye_in_speech_bubble:探索:eye_in_speech_bubble: :eagle:1、算法面试题汇总 计划如下 LeetCode探索练习:算法面试题汇总 题目\文档 完成情况 开始之前 只出现一次数字 :check_mark: 多数元素 :cross_mark: 搜索二维矩阵 :cross_mark: 合并两个有序数组 :cross_mark: 鸡蛋掉落 :cross_mark: 主题要点 首先,理清这些重要问题类型 :check_mark: 其,掌握你的学习方向 :check_mark: 字符串 验证回文子串 :check_mark: 分隔回文串 :cross_mark: 单词拆分 :cross_mark: 单词拆分|| :cross_mark: 实现Trie(前缀树) :cross_mark: 单词搜索 :cross_mark: 有效的字母异位词 :cross_mark: 字符串中的第一个唯一字符 :check_mark: 翻转字符串 :check_mark: 数组 乘积最大子数组 :cross_mark: 多数元素 :cross_mark: 旋转数组 :cross_mark: 存在重复元素 :check_mark: 移动零 :check_mark: 打乱数组 :cross_mark: 两个数组的交集 II :cross_mark: 递增的三元子序列 :cross_mark: 搜索二维

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值