5@TOC
背景
- 异或^满足结合律和交换律
- a=0 ^ a
- 0=a ^ a
- a=a^ b ^b
- 交换a和b:
a=a ^ b
b=a ^ b
a=a ^ b
整理得:
b=a ^ b ^ b=a
a=a ^ b ^ b ^ a ^ b=a ^ a ^ b=b
只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
class Solution {
public:
int singleNumber(vector<int>& nums) {
int result=0;
for(auto e:nums){
result^=e;
}
return result;
}
};
只出现一次的数字 II
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。
思路: 某一位上1出现的次数除以三的余数一定是1或者0;
class Solution {
public:
int singleNumber(vector<int>& nums) {
int result=0;
for(int i=0; i<32;i++){
int sum=0;
for(auto e:nums){
int n=e>>i;
int tmp=n & 1;
sum+=tmp;
}
cout<<"i"<<i<<"sum"<<sum<<endl;
result |=(sum%3)<<i;
}
return result;
}
};
class Solution {
public:
vector<int> singleNumber(vector<int>& nums) {
int tmp_result=0;
int tmp_result1=0;
int tmp_result2=0;
int i;
vector<int> result;
for(int e: nums){
tmp_result^=e;
}
for(i=0;i<32;i++){
int n=tmp_result>>i;
int tmp=n&1;
if(tmp==1){
break;
}
}
for(int e: nums){
int n=e>>i;
int tmp=n&1;
if(tmp==1){
tmp_result1^=e;
}else{
tmp_result2^=e;
}
}
result.push_back(tmp_result1);
result.push_back(tmp_result2);
return result;
}
};
比特位计数
给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。
思路: 利用二叉树的层次遍历,左儿子比特数不变,右儿子比特数加一。
class Solution {
public:
vector<int> countBits(int num) {
queue<pair<int,int>> que;
que.push(make_pair(1,1));
vector<int> result;
result.push_back(0);
if (num==0){
return result;
}
while(!que.empty()){
auto tmp=que.front();
que.pop();
auto n=tmp.first;
auto bit=tmp.second;
if(n==num){
result.push_back(bit);
break;
}else{
result.push_back(bit);
que.push(make_pair(n<<1,bit));
que.push(make_pair((n<<1)+1,bit+1));
}
}
return result;
}
};
数字范围按位与
给定范围 [m, n],其中 0 <= m <= n <= 2147483647,返回此范围内所有数字的按位与(包含 m, n 两端点)。
思路: 转换为求最长公共前缀,因为某一位上不同的话后一位肯定不同
class Solution {
public:
int rangeBitwiseAnd(int m, int n) {
int tmp1;
int tmp2;
int i;
for(i=0; i<32; i++){
tmp1=m>>i;
tmp2=n>>i;
if(tmp1==tmp2){
break;
}
}
return tmp1<<i;
}
};
剑指 Offer 56 - I. 数组中数字出现的次数
一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
示例 1:
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
示例 2:
输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]
限制:
2 <= nums.length <= 10000
思路: 假设那两个数为a,b,异或和为x。所有数字异或和等于x,找到x中为1的那一位index,说明在index位上a,b不同。把所有数字按照index位分为两组,就转换成两个在一组数字中求一个特殊数字的问题。
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
int len=nums.size();
int sum=0;
int a=0;
int b=0;
int tmp;
int index;
vector<int> result;
for(int i=0;i<len;i++){
sum^=nums[i];
}
for(index=0;index<32;index++){
if((sum>>index)&1==1){
break;
}
}
for(int i=0;i<len;i++){
if((nums[i]>>index)&1==1){
a^=nums[i];
}else{
b^=nums[i];
}
}
result.push_back(a);
result.push_back(b);
return result;
}
};
29. 两数相除
给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。
返回被除数 dividend 除以除数 divisor 得到的商。
整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2
示例 1:
输入: dividend = 10, divisor = 3
输出: 3
解释: 10/3 = truncate(3.33333…) = truncate(3) = 3
示例 2:
输入: dividend = 7, divisor = -3
输出: -2
解释: 7/-3 = truncate(-2.33333…) = -2
提示:
被除数和除数均为 32 位有符号整数。
除数不为 0。
假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231, 231 − 1]。本题中,如果除法结果溢出,则返回 231 − 1。
思路: 使用原码除法,要把每个负数转为正数,使用int表示数时,而-int_min会溢出,所以改用long。
使用补码除法虽然不用把负数转成正数,但是求余数时可能涉及int_min的减法,所以还是要用long。
class Solution {
public:
int divide(int dividend, int divisor) {
bool flag1=dividend>0;
long dividendLong=dividend;
if(!flag1){
dividendLong=-dividendLong;
}
bool flag2=divisor>0;
long divisorLong=divisor;
if(!flag2){
divisorLong=-divisorLong;
}
if(dividendLong==0 || divisorLong>dividendLong){
return 0;
}
bool flag=!((flag1)^(flag2));
int zNum1=0,zNum2=0;
unsigned int t=1<<31;
while(true){
if((dividendLong & t)==t){
break;
}else{
t=t>>1;
zNum1+=1;
}
}
t=1<<31;
while(true){
if((divisorLong & t)==t){
break;
}else{
t=t>>1;
zNum2+=1;
}
}
long result=0;
long level=zNum2-zNum1;
long r=dividendLong;
long y=divisorLong<<level;
long tmp;
for(;level>=0;level--){
tmp=r-y;
if(tmp>=0){
result|=long(1)<<level;
y=y>>1;
r=tmp;
}else{
y=y>>1;
}
}
if(!flag){
result= -result;
}
if(result<INT_MIN){
result=INT_MIN;
}
if(result>INT_MAX){
result=INT_MAX;
}
cout<<1-INT_MIN;
return result;
}
};