LintCode 83. Single Number II (Medium)

LeetCode 137. Single Number II (Medium)

以下算法的复杂度都是:

时间复杂度: O(n)

空间复杂度: O(1)

解法1. 32个计数器

最简单的思路是用32个计数器, 满3复位0.

class Solution {
public:
int singleNumberII(vector<int> &A) {
int cnt[32] = {0};
int res = 0;
for (int i = 0; i < 32; ++i) {
for (int n : A) {
cnt[i] += (n >> i) & 1;
cnt[i] %= 3;
}
res |= cnt[i] << i;
}
return res;
}
};

解法2. 找规律

我的思路是, 解法1中的计数其实只需要两个bit就够了. 所有的首个bit记做res, 所有的第二个bit记做carry, 找规律:

如果A[i]的第k位是0, 则res和carry的第k位保持原样.

如果A[i]的第k位是1, 则:

res carry res' carry'
0 0 1 0
1 0 0 1
0 1 0 0

此时(A[i][k]=1时)的规律就是:

res'[k]=~res[k] & ~carry[k]

carry'[k]=res[k] & ~carry[k]

class Solution {
public:
int singleNumberII(vector<int> &A) {
int res = 0, carry = 0;
for (int n : A) {
for (int i = 0; i < 32; ++i) {
int mask = (1 << i);
int bit = n & mask;
if (bit) {
int newRes = (~mask & res) + ((~res & mask) & (~carry & mask));
carry = (~mask & carry) + ((res & mask) & (~carry & mask));
res = newRes;
}
}
}
return res;
}
};

解法2.1. 解法2的简化

解法2中, 将A[i][k]=0和=1的情况合并, 可以得到:

res'[k]=(A[i][k] & ~res[k] & ~carry[k]) | (~A[i][k] & res[k])

carry'[k]=(A[i][k] & res[k] & ~carry[k]) | (~A[i][k] & carry[k])

这样的好处是可以32位一起算, 而不用一位一位地算:

res'=(A[i] & ~res & ~carry) | (~A[i][k] & res)

carry'=(A[i] & res & ~carry) | (~A[i][k] & carry)

class Solution {
public:
int singleNumberII(vector<int> &A) {
int res = 0, carry = 0;
for (int n : A) {
int newRes = (n & (~res & ~carry)) | (~n & res);
carry = (n & (res & ~carry)) | (~n & carry);
res = newRes;
}
return res;
}
};

解法3. one, two, three

Discuss中看到的解法, 自己实在想不出来. 用one, two和three三个int值作为bit flags.

循环对A[0]到A[n]进行考察, 当考察A[i]时:

记S[i]={A[0],...,A[i]},

若S[i]中所有数字的第k位bit的数目%3==1, 则one的第k位为1, 否则为0.

若S[i]中所有数字的第k位bit的数目%3==2, 则two的第k位为1, 否则为0.

而three是一个临时变量, 用于记录这一轮中, 哪些bit的数目恰巧是3的倍数.

two |= one & n;: 给two加上那些从1到2的数字.

one ^= n;: 这句比较巧妙, 既删掉了会变成2的那些1, 又加上了新的1.

three = one & two;: 1+2=3...

one&= ~three: 从1中刨去那些成为3的1.

two&= ~three: 从2中跑去那些成为3的2.

...如果你能解释得更清晰易懂, 欢迎留言!

class Solution {
public:
int singleNumberII(vector<int> &A) {
int one = 0, two = 0, three = 0;
for (int n : A) {
two |= one & n;
one ^= n;
three = one & two;
one &= ~three;
two &= ~three;
}
return one;
}
};

解法3.1. 解法3的变形

自己没想出解法4, 但是参照它的思路, 写了一个对自己比较直观的算法.

three = two & n;: 算出从2变成3的那些2.

two = (two & ~three) | (one & n);: (two & ~three)是从2中刨去那些变为3的2, (one & n)是加上那些从1变成2的1.

one = (one & ~n) | (n & ~three & ~two);: (one & ~n)是从1中刨去那些变成2的1, (n & ~three & ~two)是加上那些没给"2变3"或"1变2"用过的1.

class Solution {
public:
int singleNumberII(vector<int> &A) {
int one = 0, two = 0;
for (int n : A) {
int three = two & n;
two = (two & ~three) | (one & n);
one = (one & ~n) | (n & ~three & ~two);
}
return one;
}
};

[OJ] Single Number II的更多相关文章

  1. 【leetcode】Single Number && Single Number II(ORZ 位运算)

    题目描述: Single Number Given an array of integers, every element appears twice except for one. Find tha ...

  2. 【题解】【位操作】【Leetcode】Single Number II

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

  3. Single Number,Single Number II

    Single Number Total Accepted: 103745 Total Submissions: 218647 Difficulty: Medium Given an array of ...

  4. leetcode 之 Single Number II

    问题来源:Single Number II 问题描述:给定一个整数数组,除了一个整数出现一次之外,其余的每一个整数均出现三次,请找出这个出现一次的整数. 大家可能很熟悉另一个题目(Single Num ...

  5. 【leetcode78】Single Number II

    题目描述: 给定一个数组,里面除了一个数字,其他的都出现三次.求出这个数字 原文描述: Given an array of integers, every element appears three ...

  6. leetcode 136. Single Number 、 137. Single Number II 、 260. Single Number III(剑指offer40 数组中只出现一次的数字)

    136. Single Number 除了一个数字,其他数字都出现了两遍. 用亦或解决,亦或的特点:1.相同的数结果为0,不同的数结果为1 2.与自己亦或为0,与0亦或为原来的数 class Solu ...

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

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

  8. 【LeetCode】137. Single Number II (3 solutions)

    Single Number II Given an array of integers, every element appears threetimes except for one. Find t ...

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

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

随机推荐

  1. wamp优化

    友情链接:IT狂人博客 转载请注明作者:浮沉雄鹰 和本文链接:http://www.cnblogs.com/xby1993/p/3342085.html 一.修改php.ini, 修改上传文件大小限制 ...

  2. 【html】【19】高级篇--大事件时间轴

    下载: http://sc.chinaz.com/jiaoben/131112181390.htm 其它: http://sc.chinaz.com/tag_jiaoben/shijianzhou.h ...

  3. [leetcode]352. Data Stream as Disjoint Intervals

    数据流合并成区间,每次新来一个数,表示成一个区间,然后在已经保存的区间中进行二分查找,最后结果有3种,插入头部,尾部,中间,插入头部,不管插入哪里,都判断一下左边和右边是否能和当前的数字接起来,我这样 ...

  4. Pascal Language: Recommended Materials

    Recommended materials: http://www.marcocantu.com/epascal/

  5. Windows server2008/2012 安装oracle 11 创建实例HANG住在百分之2

    Windows server2008/2012 安装oracle 11.2.0.1的时候,可能会在创建数据库实例的时候卡在百分之2的地方. 这个时候可以 1.点击开始菜单,在“搜索程序和文件”中输入“ ...

  6. 【转】WPF获取外部EXE图标最简单的方法

    首先在工程添加对System.Drawing的引用 创建以下方法: public static ImageSource GetIcon(string fileName) { System.Drawin ...

  7. 关于Angular.js Routing 的学习笔记(实现单页应用)

    最近开始学习angular.js,发现angular.js确实很方便,也很强大.在看到 AngularJS Routing and Multiple Views 这一部分的时候,有点乱.现在通过记录一 ...

  8. GAC write failed when upgrade with InstallShield

    在接近final-build的时候,突然发现当前版本从上一个版本upgrade的时候,需要写到GAC (Global Assembly Cache)的assambly会写失败掉.但是只会在特定的Mic ...

  9. 【python】疯了,掉坑里出不来了

    学软件最头疼的事情就是版本换来换去: 各种配置错误,疯了,疯了--

  10. slqplus 帮助手册

    1.查看sqlplus的帮助是否可用,必须登录了才可用. D:\app\product\\db_1\sqlplus\admin\help>sqlplus /nolog SQL :: Copyri ...