前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >独一无二的“你”

独一无二的“你”

作者头像
鹏-程-万-里
发布2020-06-16 15:42:10
3320
发布2020-06-16 15:42:10
举报

一、只出现一次的数字

LeetCode T136 ---> 只出现一次的数字【简单题】

题目描述

【题目描述】一个数组中其他元素都出现了两次,然而只有一个元素出现了一次,我们需要找到这个特殊的数字。

1、解题思路

看到题目,我们当然很好想到使用HashMap来遍历整个数组就好了。当然,小白这里就不介绍这种解法了,换一个舒服的解法吧!

我们学过《数字电路》的小伙伴应该都知道异或运算符。相同的两个数字异或结果为0,任何数字与0异或的结果都为该数字本身,且异或运算具有交换律。即:

代码语言:javascript
复制
a ^ a = 0
a ^ 0 = a
a ^ b ^ a = a ^ a ^ b = 0 ^ b = b

由上面的基本规则,我们便可推导出本题的解法啦~

在本题中,给定了一个数组,里面有一个元素只出现了1次,其他的元素都出现了2次。所以我们根据上面异或运算的结论,将其应用到本题中,我们直接遍历整个数组,将所有的元素都使用异或运算,相同的元素经过异或运算后,结果为0,之后只剩下了0和出现一次的数字。异或结果就是这个只出现一次的数字啦~

2、代码实现
代码语言:javascript
复制
    public int singleNumber(int[] nums) {
        int ans = 0;
        for (int i = 0 ; i < nums.length ; i++ ){
            ans = ans ^ nums[i];
        }
        return ans;
    }

二、只出现一次的数字(升级版)

LeetCode T260 ---> 只出现一次的数字III【中等题】

题目描述

1、解题思路

这个升级版是在上一道的题基础上增加了一个新的条件,整个数组中有两个只出现1次的元素,其他的元素都出现了两次。

在这种情况下,如果我们再将所有的元素异或,得到是这两个只出现一次的数字异或的结果,并无法得到这两个数字。但是隐隐约约的能够感受到,这道题还是可以使用上一道题的解法的(哈哈,这可能就是直觉吧!)

我们再来分析一下无法直接使用上面一道题的解法的原因:问题在于,给定的数组中包括了两个只出现一次的元素,所以我们无法异或运算。可是,如果我们将这两个数字划分到两个不同的数组中,这样,每一个子数组就仅仅包含一个只出现一次元素了~

OK!分析到这里,我们下一个问题来了,如何将这两个元素划分到不同的数组中呢?这里就是本题的亮点啦!

我们知道,任何两个不同的数字二进制表示中,一定会至少有某一位是不同的。如果我们找到这两个数字不同的二进制位,那么就可以根据这个不同的二进制位,将两个数字分开啦~同时也可以根据这个不同的位,来将其他的所有元素区分开。而我们将所有元素异或之后,得到的结果,恰巧就是这两个数字不同的二进制位。

我们举个例子吧!元素数组nums = [1,1,2,2,3,4]

代码语言:javascript
复制
将nums中所有元素异或
ans = 1 ^ 1 ^ 2 ^ 2 ^ 3 ^ 4 = 0 ^ 0 ^ 3 ^ 4 = 3 ^ 4

十进制		 3 ^ 4	=	7

二进制		011 ^ 100 = 111

如上所示,我们当我们将所有元素异或运算之后,我们就可以得到一个ans,这个结果就代表这两个数字不同的二进制位。假如我们取ans的最低位的1,那么,我们就可以根据这个二进制位将所有的元素划分为两组了。由于数组中的其他元素都是重复出现的,所以根据这个二进制位的划分,会将相同的元素划分到相同的分组中。比如:在这个例子中,我们根据ans的最低位1,也就是数字1来划分的话,就可以看到下面的结果

代码语言:javascript
复制
第一组:1 , 1 , 3
第二组:2 ,2 ,4

其中,第一组的最低位都是1,第二组的最低位都是0,此时我们的目标元素3和4都已经在不同的分组中了,所以我们直接对两组元素异或操作,即可得到最后的结果了~

【注意】在此处我们需要说明一点,之所以我们是根据最低位来将所有元素分为两组,是基于两个只出现一次的元素(3和4)的最低位是不同的。如果这两个元素的最低位相同,则需要在两个数字的二进制位上继续向前探索,查看任何一个不同的二进制位即可。

2、代码实现
代码语言:javascript
复制
    public int[] singleNumbers(int[] nums) {
        int k = 0;
        for(int num : nums){//获取两个只出现一次的数字的异或结果
            k = k^num;
        }
        int target = 1;
        while((target & k) == 0){//寻找异或结果K的不为0的最低位
            target = target << 1;
        }
        int a = 0 , b = 0;
        for(int num:nums){//对两个数字进行分组,并且在不同的分组当中
            if((num & target) == 0){
                a = a^num;
            }else{
                b = b^num;
            }
        }
        return new int[]{a, b};
    }
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-06-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java小白成长之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、只出现一次的数字
    • 二、只出现一次的数字(升级版)
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档