zoukankan      html  css  js  c++  java
  • 40、数组中出现一次的数字

    方法一、遍历数组,最坏时间复杂度o(n2)

    方法二、HASH表O(n)

    方法三、先排序,然后比较周围两个数是否相等O(nlogn)

    方法四:异或(最优解)

    题目一、数组中出现一次的数字(一个数字)

      将整个数组做异或操作,得出的数就是只出现一次的数字

    题目二、数组中出现一次的数字(两个数字)

    • 先将整个数组做异或操作,得到的是两个不同数字的那个值异或出来的值
    • 得到值的从右边的第一个1就是我们分组的依据
    • 根据整个位是否为1,将原数组分为两组
    • 让整个两个数组分别跟自己做异或操作,最后得到的结果就是我们要求的两个数字

    题目三、数组中出现一次的数字(三个数字)

      如果我们把数组中所有数字都异或起来,那最终的结果(记为x)就是a、b、c三个数字的异或结果(x=a^b^c)。其他出现了两次的数字在异或运算中相互抵消了。

      我们可以证明异或的结果x不可能是a、b、c三个互不相同的数字中的任何一个。我们用反证法证明。假设x等于a、b、c中的某一个。比如x等于a,也就是a=a^b^c。因此b^c等于0,即b等于c。这与a、b、c是三个互不相同的三个数相矛盾。

      由于x与a、b、c都各不相同,因此x^a、x^b、x^c都不等于0

      我们定义一个函数f(n),它的结果是保留数字n的二进制表示中的最后一位1,而把其他所有位都变成0。比如十进制6表示成二进制是0110,因此f(6)的结果为2(二进制为0010)。f(x^a)、f(x^b)、f(x^c)的结果均不等于0

      接着我们考虑f(x^a)^f(x^b)^f(x^c)的结果。由于对于非0的n,f(n)的结果的二进制表示中只有一个数位是1,因此f(x^a)^f(x^b)^f(x^c)的结果肯定不为0。这是因为对于任意三个非零的数i、j、k,f(i)^f(j)的结果要么为0,要么结果的二进制结果中有两个1。不管是那种情况,f(i)^f(j)都不可能等于f(k),因为f(k)不等于0,并且结果的二进制中只有一位是1

      于是f(x^a)^f(x^b)^f(x^c)的结果的二进制中至少有一位是1。假设最后一位是1的位是第m位。那么x^a、x^b、x^c的结果中,有一个或者三个数字的第m位是1

    接下来我们证明x^a、x^b、x^c的三个结果第m位不可能都是1。还是用反证法证明。如果x^a、x^b、x^c的第m位都是1,那么a、b、c三个数字的第m位和x的第m位都相反,因此a、b、c三个数字的第m位相同。如果a、b、c三个数字的第m位都是0,x=a^b^c结果的第m位是0。由于x和a两个数字的第m位都是0,x^a结果的第m位应该是0。同理可以证明x^b、x^c第m位都是0。这与我们的假设矛盾。如果a、b、c三个数字的第m位都是1,x=a^b^c结果的第m位是1。由于x和a两个数字的第m位都是1,x^a结果的第m位应该是0。同理可以证明x^b、x^c第m位都是0。这还是与我们的假设矛盾。

      因此x^a、x^b、x^c三个数字中,只有一个数字的第m位是1。于是我们找到了能够区分a、b、c三个数字的标准。这三个数字中,只有一个数字满足这个标准,而另外两个数字不满足。一旦这个满足标准数字找出来之后,另外两个数字也就可以找出来了。

  • 相关阅读:
    Python时间戳
    vux x-input 清除按钮不起作用
    MySQL连接查询流程源码
    Linux下用的脚本
    TableCache设置过小造成MyISAM频繁损坏 与 把table_cache适当调小mysql能更快地工作
    批量导入数据到InnoDB表速度优化
    DBA面对新mysql环境
    (进阶篇)PHP+Mysql+jQuery找回密码
    (进阶篇)PHP实现用户注册后邮箱验证,激活帐号
    (实用篇)php官方微信接口大全(微信支付、微信红包、微信摇一摇、微信小店)
  • 原文地址:https://www.cnblogs.com/zxx930929/p/7927692.html
Copyright © 2011-2022 走看看