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, 则rescarry的第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, twothree三个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. -exec和|xargs

    注意xargs会被空格割裂,所以遇到带有空格的文件名就不好办了,解决方法是使用-print0 例如:删除.目录下30天之前的.png文件 -type f -name rm 或者使用-exec:删除.目 ...

  2. strcpy(),string使用问题

    两个CString,把一个赋值给另外一个,用strncpy出现问题,直接=赋值正确了,不知道为什么?

  3. 使用C++11安全的在线程中控制UI

    本篇文章由:http://www.sollyu.com/using-the-c11-secure-online-process-control-ui/ 说明 首先这里使用的是 Visual Studi ...

  4. 文件服务——Vsftpd

    文件传输协议(FTP): 能够让用户在互联网中上传.下载文件的文件协议,FTP服务就是支持FTP传输协议的主机,要想完成文件传输则需要FTP服务端和FTP客户端的配合才行. 通常用户使用FTP客户端软 ...

  5. [转]优化PHP程序的方法

    1. If a method c++an be static, declare it static. Speed improvement is by a factor of 4. 如果一个方法可静态化 ...

  6. Eat that Frog

    Eat that Frog,中文翻译过来就是“吃掉那只青蛙”.不过这里并不是讨论怎么去吃青蛙,而是一种高效的方法. Eat that Frog是Brian Tracy写的一本书(推荐阅读).这是一个很 ...

  7. Date、String、Calendar类型之间的转化

    原文出处:http://fjfj910.iteye.com/blog/1202219 1.Calendar 转化 String  //获取当前时间的具体情况,如年,月,日,week,date,分,秒等 ...

  8. centos不能挂在ntfs

    root@s 下载]# mount /dev/sdb1 /mnt mount: unknown filesystem type 'ntfs' wget http://www.tuxera.com/co ...

  9. json在线校验

    弄了一个在线校验,清爽无广告,欢迎大家收藏   http://www.zhhoney.com/

  10. Vijos P1003 等价表达式 随机数+单调栈

    题目链接:https://vijos.org/p/1003 题意: 1. 表达式只可能包含一个变量‘a’. 2. 表达式中出现的数都是正整数,而且都小于10000. 3. 表达式中可以包括四种运算‘+ ...