LeetCode题解2020/5/14 只出现一次的数字 系列

LeetCode 136.只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

我的思路:

这个题在Leetcode的难度是比较简单的,如果不是受限于额外空间的要求,那么用一个Set集合的话比较容易解决问题(个人习惯)

但是不需要额外空间的话,那就涉及到今天题解着重触及到的一个内容。

位运算。

首先来明确有哪些运算?与,或,非,异或

XOR(异或)正是解决我们这个题目的一个位运算思路。XOR:相同为0,相异为1.

0 XOR 1 XOR 1=0 

1 XOR 1 XOR 1=1 

1 XOR 0 XOR 0=1

0 XOR 0 XOR 0=0

我们注意到关于异或的一个结论就是:一个数如果连续异或了两个相同的数,他将保持不变。

对于这个题而言,我们注意到如果我设置一个变量为0,让他去异或这个数组中所有的数。最后得到的结果将是0异或那个只出现1次的数的结果,因为其他数都出现两次,至此,问题迎刃而解。

0XOR0=0 0XOR1=1,所以这个异或的结果正是我们要求的那个只出现了一次的数。

Leetcode 137.只出现一次的数字 Ⅱ

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。

问题变成了每个元素3次,我们又如何通过位运算的思路解决问题呢,这时我们从样例开始分析:

2 二进制表示0 0 1 0

2 二进制表示0 0 1 0

2 二进制表示0 0 1 0

3 二进制表示0 0 1 1

加起来是多少0 0 4 1

除3可得余数0 0 1 1(这个思路要感谢评论区精选评论Krahets的题解,有图作示例且十分清晰)

0 0 1 1 正是我们要求的3,因为三次出现的数在除3的过程中被筛选掉了,如何实现这么一个筛选过程呢?

引入自动机。(笔者本学期学编译原理的时候接触了自动机理论)

这个自动机正是解决了这样的问题,最后可能停到0或1的状态上(不可能在2上了),而这个结果正是那个单独只出现一次数字的对应位数,若我们将这个方法推广到所有位数上,那我们自然可以得到这个数的一个完整的二进制表示,也就得到了这样一个数了。在逻辑判定上,位运算也可以简化我们的逻辑。若是我们用二进制表示0,1,2分别为00,01,10,那么有

one = one XOR num AND ~two;(one为第一位,two为第二位,num为对应位数上是0还是1,可直接推广到全数)

two = two XOR num AND ~one;(~为取反)

等价于

if(two == 0&&n==0)one=one;
else if(two==0&&n==1)one=~one;
else one=0;

if(two == 0&&n==0)two=two;
else if(two==0&&n==1)two=~two;
else two=0;

Leetcode 260.只出现一次的数字 Ⅲ

给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。

这道题还是从位运算的角度出发,还是用类似于第一问的异或的思路。

最后异或的结果必然是恰好只出现一次的两个元素的异或值,如何把两个区分开来呢?

自己与自己的负值的异或可以保留最右侧的1,最右侧的1代表着最右部第一个两个数字不相同的位,要么来自x,要么来自y

利用这个1将整个数组或容器内的数分成两组,再对两组按I问操作分别求掩码,即可获得两个数(或只求一组,再用总的掩码异或也可以)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值