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?
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;
}
};