[leetcod] 从 “寻找故障机器” y&II 的一点启发

先从编程之美中一道叫做“寻找故障机器”的题目说起,题目大意是 一个数组,其中只有一个数字出现了一次,其他都出现了两次,问怎样快速找到那个出现了一次的数字。这也就是leetcode上Single Number I这道题。当然了,我们有个对于空间和时间的限制,限制空间为O(1),时间为线性的。若做过这种题,或者经过自己一步步的思考,或许可以想到这个巧妙的方法:将所有数组中的数全部抑或,最后剩下的那个,就一定是只出现一次的数字。说实话一直感觉这种做法很不可思议,只用了一个int的内存就完成了正常O(N)空间才可以完成的,但是,当然了,用O(N)的额外空间遍历时可以记录并“还原”中间出现过的数字,而把他们一股脑抑或,中间过程中,他都是无意义的,只有特定地,只出现一个单独的,其他全是成对,最后的结果才有意义。

然后今天有遇到了这道题的威力加强版,题目如下:

Given an array of integers, every element appears three times except for one. Find that single one.

好了,现在每个数都出现三次,最后一个数可能出现一到两次。说实话一开始太笨,并没有联想到用类似的解法,看到了别人的讨论,才想到可以用类似的方法去做。

考虑每个数都出现两次,我们用到了抑或操作,对于一个数的每位而言,抑或操作其实等价于这个真值表。

result  nextnum   result

0 0

0 1 1

1 0 1

1 1 0

因为每个数都出现两次时有两种状态,0和1,来了0不变,来了1,0变1,1回到0。

拓展来,每个数都出现三次时,每个数就有三种状态,0,1,2 我们自然想到将一个result用两个数分开表示

result nextnum  result

a b a b

0 0 0 0

0 0 1 1

1 0 0 1

1 1 1 0

0 0 1 1

1 1 1 0 0

  这个想法和上面那个类似。

弄出来了真值表我们要用表达式给它表示出来,输入是a b c输出是a b

还记得大二时候学电路逻辑时候,还学到了这种表达方法和化简方法,还记得卡诺图么。。。还记得什么摩根定理么。。。想知道怎么化简自己去查吧~在这里不说了

我们用更简单直接的方法,例如求输出a的表达式,把红色为1的找出来,然后就可以写出 a=(~a&b&nextnum)+(a&~b&~c)

最后上源码:

public class Solution {
    public int singleNumber(int[] nums) {
        int a=0;
        int b=0;
        for(int c:nums){
            int t
empa=(~a&b&c)|(a&~c);//我们这里两个表达式用了卡诺图化简
            b=(~a&~b&c)|(b&~c);
            a=t
empa;
            
        }
        return a|b;
    }
}

最后为什么是a|b呢,可以自己思考下,提示(单独那个数可能出现一次,也可能出现两次)。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值