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

题意: 在一个整型数组里,只有一个数字出现一次,其他数字都出现了3次,求这个只出现一次的数字(single number)。

这真是非常非常有意思的一道题目。如果直接统计各数字出现的次数当然也能达到目的,不过空间复杂度为O(N)。能否用O(1)空间解决此问题呢?

首先注意到,对于某个二进制位,如果single number的该位为1,那么所有数字在该二进制位上1出现的总次数不能被3 整除,且余数为1。比如数组{3, 3, 3, 2},转化为二进制表示: {11, 11, 11, 10},二进制位01出现的次数为3次,二进制位10出现的次数为4次。

因此我们只需要计算出每个二进制位1出现次数除以3的余数,就可以轻松得到该single number。

模3的余数有3个: 0, 1, 2,对应二进制表示: 00, 01, 10,需要两个二进制位来表示。

我们可以用两个整数one和two来分别表示各二进制位1出现的次数模3的余数。

显然直接累加统计次数然后取模是不现实的,这时候就要用到位运算了,这也是本题解法最有技巧的一部分。

如何设计位运算模拟累加模3的结果呢?

假设当前累加到数组中的数字num,考察one,two和num在二进制位取不同值下,累加1的出现次数模3的结果:

One'和Two'分别表示累加后模3的新余数的第一位和第二位。

举例

假设当前二进制位1出现的次数模3为1,数字num在该二进制位为0,那么1的出现次数不变,模3依然为1,对应两个真值表的第二行: One' = 1, Two' = 0。

假设当前二进制位1出现的次数模3为2,数字num在该二进制位为1,那么1的出现次数+1,模3结果变为0,对应两个真值表的第四行: One' = 0, Two' = 0。

因此,以上真值表就包含了所有情况下累加模3的结果。

如何将真值表转化为位运算的逻辑表达式呢?这时候就要用到一个大杀器:卡诺图 (Karnaugh map)

以下是两个真值表转化来的卡诺图:

One'

Two'

解释:

列头表示num在该位为0或1的情况,行头表示当前余数的值。

两张表表内的0和1分别表示给定num和余数,进行累加模3操作后,One' 和 Two'的值,大家可以对比之前的真值表体会一下。

注意余数为11的情况是不存在的,因此结果标记为x,这列其实可以删掉。之所以写出来是为了体现卡诺图的逻辑条件是按格雷码排列的,简单说就是相邻的二进制条件只有1位是不一样的。这样方便转化为逻辑表达式的时候进行化简,简单说就是卡诺图里相邻并且构成矩形的1的情况可以简化为用一个逻辑表达式来表示。具体可以参考卡诺图Wiki页面的例子。这个问题的卡诺图比较简单,不存在化简的情况。

接下来将卡诺图转换为逻辑表达式。

以One'为例。图中只有两个格子为1,也即num = 0, two = 0, one =1 和 num = 1, two = 0, one = 0的情况。因此我们有:

one = (~num & ~two & one) + (num & ~one & ~two);

只有以上两种情况之一,one可以取值1,其他情况皆为0。注意C++里位操作符&, ^, |等的优先级低于加法操作符,因此需要括号括起来。

Two的逻辑表达式可以类推。

以下为完整代码。因为single number的1只出现一次,模3余数肯定为1,因此直接返回one即可。

int singleNumber(vector<int>& nums) {
int one = , two = ;
for (int i = ; i < nums.size(); i++) {
int num = nums[i];
int newOne = (~num & ~two & one) + (num & ~one & ~two);
two = (~num & two & ~one) + (num & ~two & one);
one = newOne;
} return one;
}

详解LeetCode 137. Single Number II的更多相关文章

  1. LeetCode 137. Single Number II(只出现一次的数字 II)

    LeetCode 137. Single Number II(只出现一次的数字 II)

  2. Leetcode 137 Single Number II 仅出现一次的数字

    原题地址https://leetcode.com/problems/single-number-ii/ 题目描述Given an array of integers, every element ap ...

  3. LeetCode 137 Single Number II(仅仅出现一次的数字 II)(*)

    翻译 给定一个整型数组,除了某个元素外其余的均出现了三次. 找出这个元素. 备注: 你的算法应该是线性时间复杂度. 你能够不用额外的空间来实现它吗? 原文 Given an array of inte ...

  4. [LeetCode] 137. Single Number II 单独数 II

    Given a non-empty array of integers, every element appears three times except for one, which appears ...

  5. [LeetCode] 137. Single Number II 单独的数字之二

    Given a non-empty array of integers, every element appears three times except for one, which appears ...

  6. leetcode 137. Single Number II ----- java

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

  7. Java [Leetcode 137]Single Number II

    题目描述: Given an array of integers, every element appears three times except for one. Find that single ...

  8. LeetCode 137 Single Number II 数组中除了一个数外,其他的数都出现了三次,找出这个只出现一次的数

    Given an array of integers, every element appears three times except for one, which appears exactly ...

  9. Java for LeetCode 137 Single Number II

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

随机推荐

  1. recycle bin tip

    if you have a question about recycle bin that can look the follow link; http://www.dba-oracle.com/t_ ...

  2. Exchange 2016 CU6 安装后,发生错误 出现意外错误,无法处理您的请求

    公司的Exchange2016环境准备上线了,今天owa打不开了.出现如下图的错误,更多详细信息没有截图,但最关键的一句记下来了. X-OWA-Error Microsoft.Exchange.Dia ...

  3. loadrunner测试c/s架构的应用系统

    用LoadRunner测试c/s架构的软件,怎样去选择协议,困扰了我很久,看到这篇文章,感觉有点收获,所以特意转了过来,希望对大家有用. 首先,什么是协议?协议无非就是一个约定,关于数据包发送的格式的 ...

  4. August 29th 2017 Week 35th Tuesday

    Life is a pure flame, and we live by an invisible sun within us. 生命如纯洁的火焰,而维系这火焰的是我们内心的太阳. Burn my l ...

  5. December 30th 2016 Week 53rd Friday

    Life without love is like a tree without blossoms or fruit. 缺少爱的生活就像从未开花结果的枯树. Love is not only the ...

  6. ZT fcntl设置FD_CLOEXEC标志作用

    fcntl设置FD_CLOEXEC标志作用 分类: C/C++ linux 2011-11-02 22:11 3217人阅读 评论(0) 收藏 举报 bufferexegccnullfile 通过fc ...

  7. BZOJ 2440 完全平方数 莫比乌斯反演模板题

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2440 题目大意: 求第k个无平方因子的数 思路: 二分答案x,求1-x中有多少个平方因 ...

  8. cogs 2355. [HZOI 2015] 有标号的DAG计数 II

    题目分析 来自2013年王迪的论文<浅谈容斥原理> 设\(f_{n,S}\)表示n个节点,入度为0的点集恰好为S的方案数. 设\(g_{n,S}\)表示n个节点,入度为0的点集至少为S的方 ...

  9. 解决MySQL新建用户后无法登录问题

    在PHPMyAdmin里创建了一个新的用户,并且创建了密码,但是却一直无法使用这个账户登录到MySQL里. 解决过程分享给大家~ 1.以root身份登录mysql 2.删除MySQL中默认存在一个用户 ...

  10. [Python 多线程] threading.local类 (六)

    在使用threading.local()之前,先了解一下局部变量和全局变量. 局部变量: import threading import time def worker(): x = 0 for i ...