异或运算解leetcode136——只出现一次的数字

题目:给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。

示例 1 :

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

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

输入:nums = [1]
输出:1

了解异或运算的几个基本特性:

  1. 0^N=N N^N=0

  2. 异或运算符合是交换律和结合律即:a ^ b ^ c= a ^ (b ^ c) ,a ^ b ^ c = a ^ c ^ b 

  3. 在一堆数进行交换异或运算的时候,运算的结果跟运算先后是没有关系的

所以我们看到这道题时可以很轻松,只需要定义一个变量,令它为零,然后遍历整个数组依次去进行异或操作即可,我们知道出现两次的数进行异或就变成零了,那么最后整个结果就时那个只出现一次的数了。代码如下:

可以看出通过异或运算可以非常轻松的ac这道题,不止于此,我们还可以通过异或运算进行两个数的交换:示例如下:

int a=10;
int b=19;
//交换:
a=a^b;	a=10^19;
b=a^b;	b=10^19^19//因为异或有结合律,可以对后两个数先进行异或,结果为0,10^0=10;
a=a^b;	a=10^19^10=19

//交换后
a=19;
b=10;

有点小妙,这样用异或运算交换两个数就不用额外再使用一个辅助变量了;

前提:a和b这两个变量不能指向同一个地址,因为就上述例子,如果两个变量是对一个地址的,当a异或b后,a就等于0了,这是a与b指向同一个地址,b的值也被变成0了,这时候就把a跟b都置零了就达不到想要的效果了

我们还可以用异或来解决该题的进阶版:一个数组,有两种数出现了奇数次,其余的数都出现偶数次,如何找到这两个数?要求时间复杂度O(n),空间复杂度O(1):解决方法如下:

public static void printOddtimesnum2(int[] nums){
    int ero=0;
    for (int i=0;i<arr.length;i++){
        ero ^=arr[i];//得到的ero肯定是那两个奇数次的数的异或表达式 a^b
    }
    //通过题干我们可以知道,a和b是两个不同的数,那么a^b肯定不等于零 ero!=0
    //那么ero在二进制的表示上,肯定有一位,至少有一位是不为零的(为1),那么这个位上的1的来源
    //就是来自a和b在这个位上的数不同,要么a在这个位上为0,b为1,要么a为1,b为0
    int rightOne=ero & (~ero+1);//提取出最右位的1,这行代码很重要!!
    							//这个时候rightone除了最右边那个数是1以外,其他的都是0;
    int onlyOne=0;//用来储存a或者b的其中一个
    for (int i=0;i<arr.length;i++){
        if ((arr[i] & rightone)==0){//只要arr[i]在那个位上的数不是1,那么结果肯定为零,可以简单的认为数组中的数是分成两批的,一批在该位上是0,一批在该位是1,偶数次的数与上rightone结果就变成零了,奇数次的是本身,然后就可以得到其中的一个数!!
            onlyOne ^=arr[i];//得到的这个数,要么是a要么是b
        }
    }
    //因为ero是等于a^b的
    int other =ero^onlyone;//得到另一个奇数次的数,要么是a要么是b;
}

That’s all~

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值