码迷,mamicode.com
首页 > 其他好文 > 详细

Single Number II

时间:2016-07-05 11:52:06      阅读:129      评论:0      收藏:0      [点我收藏+]

标签:

The problem is similar to Single Number, two ways can solve it:

1. Traditional way: HashMap 参考之前的note

2. Bit Operation:

http://www.wengweitao.com/lintcode-single-number-i-ii-iii-luo-dan-de-shu.html

class Solution {
public:
	/**
	 * @param A : An integer array
	 * @return : An integer 
	 */
	bool isBit1(int num, int index){
        int mask = 1 << index; // left shift 1 to the bit we want to calculate eg. 0100 
        return (num & mask);  // & 0100 will set all other bit to be 0 except 1. 
                              // 1 will be same as original, so it either to be a number or 0000
    }
    
    int singleNumberII(vector<int> &A) {
        // write your code here
        int n = A.size();
        int res = 0;
        for(int i = 0; i < 32; ++i){
            int count = 0;
            for ( int j = 0; j < n; ++j){
                if(isBit1(A[j], i)){
                    count++;
                }
            }
            res |= (count % 3) << i;
        }
        return res;
    }
};

思路1:

对int的32bit的各个位中1出现的次数,对数组中所有元素的逐个进行统计,然后对每个bit对3取余,最终的结果就是只出现一次的数字。

由于x^x^x = x,无法直接利用I的方法来解。但可以应用类似的思路,即利用位运算来消除重复3次的数。以一个数组[14 14 14 9]为例,将每个数字以二进制表达:
 
1110
1110
1110
1001
_____
4331    对每一位进行求和
1001    对每一位的和做%3运算,来消去所有重复3次的数
 
public class Solution {
	/**
	 * @param A : An integer array
	 * @return : An integer 
	 */
    public int singleNumberII(int[] A) {
        // write your code here
        int n = A.length;
        int once = 0;
        int twice = 0;
        int third = 0;
        for (int i = 0; i < n; ++i){
            twice |= once & A[i]; // if it shows once, and A[i] has it again, it should set to twice;
            once ^= A[i]; //if it shows once, and A[i] has it again, it has been send to twice, once has to be set back to zero;
            third = once & twice; // if it shows once, and it shows twice, it shows three times;
            once &= ~third; //once it set to three times, set back once/twice to be zero;
            twice &= ~third;
        }
        return once;
    }
}

思路2: 利用掩码的思想。

  • 变量once作为一个掩码,若once的二进制表示中的一个位置为1,表示目前使该位为1的数只出现一次
  • 变量twice作为一个掩码,若twice的二进制表示中的一个位置为1,表示目前使该位置为1的数出现了2次
  • 变量third作为一个掩码,若third的二进制表示中的一个位置为1,表示目前使该位置为1的数出现了3次
  • 若之前出现一次(表示为once中对应的位为1),A[i]中又出现(表示为A[i]中对应的位置为1),那么twice中对应的位就为1;
  • 若之前的once中出现,而A[i]中又出现,那么就不是出现一次,将对应的位取0
  • once中出现一次,twice出现两次,也就是出现了3次
  • 需要将once和twice中出现3次的位都置为0

以上的代码涉及到比较多的位运算,可能不大好理解。举个具体的例子:

once: 100101 使第1、3、6个bit为1的数出现3次

twice: 010101 使第1、3、5个bit为1的数出现了2次

third: 000101 根据once和twice可以得到third,第1和3个bit为1的数出现了3次。

以上算法的时间复杂度为O(n),空间复杂度为O(1)。

 

 

扩展一:

给定一个包含n个整数的数组,除了一个数出现二次外所有的整数均出现三次,找出这个只出现二次的整数。ones记录1出现一次的数,twos记录1出现2次的数,容易知道twos记录的即是最终结果。

扩展二:

给定一个包含n个整数的数组,有一个整数x出现b次,一个整数y出现c次,其他所有的数均出现a次,其中b和c均不是a的倍数,找出x和y。使用二进制模拟a进制,累计二进制位1出现的次数,当次数达到a时,对其清零,这样可以得到b mod a次x,c mod a次y的累加。遍历剩余结果(用ones、twos、fours...变量表示)中每一位二进制位1出现的次数,如果次数为b mod a 或者 c mod a,可以说明x和y的当前二进制位不同(一个为0,另一个为1),据此二进制位将原数组分成两组,一组该二进制位为1,另一组该二进制位为0。这样问题变成“除了一个整数出现a1次(a1 = b 或 a1 = c)外所有的整数均出现a次”,使用和上面相同的方式计算就可以得到最终结果,假设模拟a进制计算过程中使用的变量为ones、twos、fours...那么最终结果可以用ones | twos | fours ...表示。

 

Single Number II

标签:

原文地址:http://www.cnblogs.com/codingEskimo/p/5642822.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!