部分文章内容为公开资料查询整理,原文出处可能未标注,如有侵权,请联系我,谢谢。邮箱地址:gnivor@163.com ►►►需要气球么?请点击我吧!

*LeetCode--136. Single Number(异或运算,寻找单个的元素)

()题目大意:有一个数组,除了一个元素出现了一次,所有其他元素均出现了两次,求出这个元素。

题目要求时间复杂度O(n) , 空间复杂度O(1)

 

刚读完题,想到的是使用HashMap来看元素是否重复,时间复杂度为O(n),但是空间复杂度为O(1),不满足题意。
仍然给出代码:(如果元素在map内,则删除,否则,添加进去。这样到最后只有那个单个的元素)

public static int singleNumber(int[] nums) {
    HashMap<Integer,Integer> map = new HashMap();
    int len = nums.length;
    for(int i = 0 ; i < len ; i++){
        if(map.get(nums[i])!=null)
            map.remove(nums[i]);
        else 
            map.put(nums[i], 1);
    }
    Set set = map.keySet();
    Iterator itr = set.iterator();
    return (int)itr.next();
}

 

正确解法:利用异或运算

异或运算:如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。

注意:
1. 异或运算是可交换,即 a ^ b = b ^ a
2. 0 ^ a = a

代码:

public static int singleNumber(int[] nums) {
    int len = nums.length;
    int solu = 0;
    for(int i = 0 ; i < len ; i++){
        solu = solu^nums[i];
    }
    return solu;
}


参考资料:http://www.cnblogs.com/changchengxiao/p/3413294.html

本题扩展

1.一个数组中有两个元素只出现一次,其他所有元素都出现两次,求这两个只出现一次的元素

[解题思路]

将数组所有元素都进行异或得到一个不为0的结果,根据这个结果中的不为0的某一位将数组分成两组

将两组中的元素进行异或,如两个数组的异或值都不为0,则得到最后结果

如果有两个只出现一次的数字,设定为a,b。也是应用异或,但是数组元素全部异或的结果x=a^b,因为a,b是不相同的数字,因此x肯定不为0。对于x,从低位到高位开始,找到第一个bit位为1的位置设定为第m位,这个第m位的bit肯定来自a或者来自b,不可能同时a,b的第m位(从低到高位)都为1。这样,就可以根据这个第m位就可以把数组分为两个部分,一组为第m位为0,一组为第m位为1.这样,就把问题分解成了求两个数组中只出现一次的数字了 

2.一个数组中有一个元素只出现1次,其他所有元素都出现k次,求这个只出现1次的元素

[解题思路]

当k为偶数时,同lss

当k为奇数时,将数组中每个元素转换成二进制,将对应的每一位相加mod k,得到结果即位出现1次的元素,时间复杂度O(n*len),空间复杂度为O(1)

这里以k=3为例:

//思路 : 将每一个数字转换成二进制数,
//对应的每一位相加,三个相同的数,在该位上的和只可能是0或者3
//将每一位的结果和3取余,就相当于把出现3次的数字抵消了,那么这个剩下的数字就是单下来的那个数
public static int singleNumber(int[] nums) {
    int len = nums .length;
    int temp ; 
    int res  = 0;
    for(int i = 0 ; i < 32 ; i++){
        temp = 0;            
        for(int j = 0 ; j < len ; j++)
            temp = temp + ((nums[j]>>i)&1) ;
        res = res| (temp%3)<<i;
    }
    return res;
}

 注意:上面代码中对res的计算也可以表示成:

res+( (temp%3)<<i ); 

但是注意后半部分要加上括号。
上面这种方法是一种通用的解法。还有一种针对k=3的解法:
原文见:http://www.acmerblog.com/leetcode-single-number-ii-5394.html

 

  1. ones   代表第ith 位只出现一次的掩码变量 (这个最终代表结果)
  2. twos  代表第ith 位只出现两次次的掩码变量  (出现两次的结果累计在这,注意不是加)
  3. threes  代表第ith 位只出现三次的掩码变量 (出现三次的结果累计在这,注意不是加)

 

假设在数组的开头连续出现3次5,则变化如下:

01    ones = 101
02    twos = 0
03    threes = 0
04    --------------
05    ones = 0
06    twos = 101
07    threes = 0
08    --------------
09    ones = 0
10    twos = 0
11    threes = 101
12    --------------

当第 ith 位出现3次时,我们就 ones  和 twos  的第 ith 位设置为0. 最终的答案就是 ones。

int singleNumber(int A[], int n) {
    int ones = 0, twos = 0, threes = 0;
    for (int i = 0; i < n; i++) {
    twos |= ones & A[i];
    ones ^= A[i];// 异或3次 和 异或 1次的结果是一样的
    //对于ones 和 twos 把出现了3次的位置设置为0 (取反之后1的位置为0)
    threes = ones & twos;
    ones &= ~threes;
    twos &= ~threes;
    }
    return ones;
}

 

 

 

 

posted @ 2015-07-19 17:13  流了个火  阅读(173)  评论(0)    收藏  举报
►►►需要气球么?请点击我吧!►►►
View My Stats