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. Sqlserver 理解子查询

    理解子查询: 理解子查询: 多表连接查询往往也可以用子查询进行替代 子查询本质是嵌套进其他 select update insert Delete 语句的一个被限制的select语句,在子查询中,只有 ...

  2. 错误源:WebForms UnobtrusiveValidationMode requires a ScriptResourceMapping for 'jquery'. Please add a ScriptResourceMapping named jquery(case-sensitive).

    Server Error in '/' Application. WebForms UnobtrusiveValidationMode requires a ScriptResourceMapping ...

  3. 函数strtok

    char* strtok(char *str, const char*delim) char *strtok_r(char *str, const char *delim, char **savept ...

  4. ASCII Table/ASCII表

    ASCII Table/ASCII表 参考: 1.Table of ASCII Characters

  5. spring常用的连接池属性文件配置

    (一) DBCP 引入jar文件 commons-dbcp-1.2.1.jar commons-pool-1.3.jar二个包. spring配置文件 <bean id="dataSo ...

  6. ThinkPHP3.2 加载过程(四)

    前言: 由于比较懒散,但是又是有点强迫症,所以还是想继续把ThinkPHP3.2的加载过程这个烂尾楼补充完整. ========================================分割线= ...

  7. Executors 构建线程池

    Executors包含一系列静态方法,可以用于构建线程池. 返回实现了 ExecutorService 接口的对象: newCachedThreadPool newFixedThreadPool(in ...

  8. 把URL传递参数转变成自定义实体方法

    先定义下要获取的实体: public class InputClass { public long Id { get; set; } public int Status { get; set; } p ...

  9. 【转】使用DevExpress的WebChartControl控件绘制图表(柱状图、折线图、饼图)

    第一次写博,没什么经验,主要是把最近自己对Dev的一些研究贴出来大家共同探讨,有不足之处望大家帮忙斧正. WebChartControl是DevExpress控件群下的一个Web图表控件,它使用非常的 ...

  10. 使用Adobe Photoshop CC 2015批量修改图片尺寸

    最近在工作中遇到一个问题,当时客户给的图片尺寸与我要求的图片不符,由于图片非常的多,如果一张一张的修改,十分的麻烦,后来经过一位同事的指点,发现Adobe Photoshop CC 2015可以实现批 ...