笔试面试题目:求“孤单数”(使用异或)

      很久以前,参加X公司面试,遇到这样一道题目:

      在数组中,只出现一次的数叫“孤单数”, 某数组a中有两个“孤单数”,而其余数字出现次数都为偶数次,求这两个“孤单数”。要求:时间复杂度为O(n), 空间复杂度为O(1).

      这个问题的最直观解法是:直接对数组元素进行计数。但是,这样空间复杂度必然无法满足要求,怎么办呢?

      可以考虑异或。异或,是一种重要的操作,在之前的文章中,介绍过如下电路图,其功能是计算两个1位二进制值的异或:

      D1和D2异或的结果D3如下:

D1

操作

D2

D3

0

异或

0

0

0

异或

1

1

1

异或

0

1

1

异或

1

0

     可以看到,异或其实就是不考虑进位的二进制加法。实际上,计算机中的加法就是用异或来实现的。

      那么,对于两个整数而言,它们的异或结果,就是按位异或的值,我们来看下3和5的异或:

      可以看出,a和b异或的结果如下(异或符号是^):

      1. 当a不等于b, a^b不为0;

      2. 当a=b, a^b为0;

      3. 当b=0, a^b为a.

      假如数组a中只有一个“孤单数”, 而其它数字都出现偶数次时,把所有数字异或,就会得到该“孤单数”,程序如下:

package main

import "fmt"

func findSole(a []int) int {
    n := 0
    for _, v := range a {
        n = n ^ v
    }
    
    return n
}

func main() {
    a := []int{2, 1, 2, 3, 5, 1, 3} // 只有1个“孤单数”
    fmt.Println(findSole(a)) // 5是“孤单数”
}

      回头再看实际题目,数组a中有两个“孤单数”,那怎么办呢?

      假设数组a为{2, 1, 2, 3, 5, 1},如果把所有数字异或,得到的结果是3和5的异或值(也即为6),无法分解出3和5.

      我们再观察下3和5的异或:

      可以看到,从二进制层面来看,3和5的倒数第二位分别是1和0,所以,我们可以把数组a分类两类:

      第一类: 二进制数字倒数第二位为1的数, 比如3, k1, k2, k1, k2.

      第二类: 二进制数字倒数第二位为0的数,比如5, k3, k4, k4, k3.

      现在,我们对这两类数字分别进行异或,很容易就求出了3和5这两个“孤单数”。

      异或,是一种很巧妙的思维,这取决于异或独特的性质。在实际开发中,我们会偶尔用到异或,而且,这类按位运算是非常快的。在一些笔试面试中,异或也是常考的内容之一。

      周末愉快。

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值