Leetcode - Bit Operation/Array- Single Number

1、Single Number

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

Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

解析1:利用异或的特性:A^A=0,A^B=B^A,所以对数组中所有元素异或,再利用交换律,最后的结果为A^A^B^B^C^C^...^(Single Number)。

解析2:利用accumulate函数实现累积异或操作,accumulate函数调用了functional头文件定义的bit_xor函数对象实现异或操作。(Generically, function objects are instances of a class with member function operator() defined. This member function allows the object to be used with the same syntax as a function call.)

class Solution {
public:
    int singleNumber(int A[], int n) { // 时间复杂度O(1),空间复杂度O(1)
        if(NULL==A||0==n)
            return 0;
        int result;
        for(int i=0;i<n;i++)
        {
            result^=A[i];
        }
        return result;
    }
};
class Solution {
public:
    int singleNumber(int A[], int n) { // 时间复杂度O(1),空间复杂度O(1)
        if(NULL==A||0==n)
            return 0;
        return accumulate(A,A+n,0,bit_xor<int>()); //调用numeric头文件定义的accumulate函数,bit_xor为函数对象类
    }
};


利用位运算可以提高效率以及防止溢出。以下为位运算解决的一些问题

1、二进制中1的数量:x=x&(x-1);

x&(x-1)将x的二进制表达中的最右边的1消除,利用while循环反复消除就可以计算出x的二进制表达中的1的数量。

应用1:同时也可以利用该表达式判断x是否是2的幂次,如果x&(x-1)==0则x中只有一个1,为2的幂次。

应用2:输入两个整数m和n,计算需要改变m的二进制表示中的多少位才能得到n。

第一步: 求两个数的异或;第二步:统计异或结果中1的数量。

2、用位运算实现两个整型的平均值:(x&y)+(x^y)>>1

a表示与x和y中二进制位相同的数,b表示x-a,为x中与a不同的位组成的数,c表示y-a,为y中与a不同的位组成的数,则(x+y)/2=(a+a)/2+(b+c)/2=a+(b+c)/2,明显,a=x&y,b+c=x^y。

3、不使用中间变量交换两个数

a=a+b;
b=a-b;
a=a-b; // 方案1:可能超界
a=a^b;
b=a^b;
a=a^b; //方案2

2、Single Number II 

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

Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

按照题意,n个整型32个二进制位每位的和要么是3的倍数,要么除3余1,余下来的1便是只出现一次的整型的二进制位的1.

class Solution {
public:
    int singleNumber(int A[], int n) {
        const int s_t=sizeof(int)*8;
        int count[s_t]={0};
        int result=0;
        for(int i=0;i<s_t;i++)
        {
            for(int j=0;j<n;j++)
            {
                count[i]+=(A[j]>>i)&1;
            }
            result|=(count[i]%3)<<i;
        }
        return result;
    }
};

class Solution {
public:
    int singleNumber(int A[], int n) {
        int one=0, two=0, three=0;
        // one表示二进制位出现1次(mod3之后的1)的二进制位有哪些
        // two表示二进制位出现2次(mod3之后的2)的二进制位有哪些
        // three出现3次需要清零的二进制位置0
        for(int i=0;i<n;i++)
        {
            two|=one&A[i]; // 包含出现2次和3次的二进制位
            one^=A[i]; // 包含出现1次和3次的二进制位
            three=~(one&two);
            one&=three;
            two&=three;
        }
        return one;
    }
};



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值