1.基础
- 1 按位与,很简单,1&1=1;1&0=0;0&1=0;0&0=0。有零则结果为零
- 2 按位或,1&1=1;1&0=1;0&1=1;0&0=0。有一则结果为一
- 3 按位异或,
- 4 按位取反
- 5 左移 高位溢出则丢弃,低位补0
- 6 带符号右移
- 7 无符号右移
通过题目去进一步加深理解
n >>= 1,简单的右移?
uint32_t n = 10101100;
uint32_t rev = 0;
for (int i = 1; i <= 8 ; i++) {
//rev |= (n & 1) << (31 - i);
//rev = (rev << 1) | (n & 1);
n = i;
n >>= 1;
cout <<"i: "<< i << " n: " << n << endl;
}
扩展:如何遍历一个长长的二进制呢
int main()
{
//uint32_t n = 1010;
uint32_t n = 10;// 1010
cout << n << endl;
uint32_t rev = 0;
for (int i = 1; i <= 4 ; i++) {
//rev |= (n & 1) << (31 - i);
//rev = (rev << 1) | (n & 1);
n >>= 1;
cout <<"i: "<< i << " n: " << n << endl;
}
system("pause");
return 0;
}
题190 颠倒二进制位
这是最容易想到的方法了,每次把 res 左移,把 nn 的二进制末尾数字,拼接到结果 res 的末尾。然后把 nn 右移。
举一个 8 位的二进制进行说明:
class Solution {
public:
uint32_t reverseBits(uint32_t n) {
uint32_t rev = 0;
for (int i = 0; i < 32 && n > 0; ++i) {
// 1. 分段思路
int x = n & 1; //先取出 n 的最低位
x <<= (31 - i); //再将这最低位左移到对应的位置
rev = rev | x; //然后放到 rev 当中
n>>=1; // 修改 n 的最低位
// 2. 总结思路
//rev |= ((n & 1) << (31 - i) );
//n>>=1;
}
return rev;
}
};
题191 位1的个数
class Solution {
public:
int hammingWeight(uint32_t n) {
int ret = 0;
for (int i = 0; i < 32; i++) {
int x = n & 1;
if (x>=1){
ret++;
}
n>>=1;
}
return ret;
}
};
题476 数字的补数
class Solution {
public:
int findComplement(int num) {
long shit=(long)num;
long n=1;
while (n<=shit){ // 这边不断的改变 1 的位置,来和num比较,从而得知num处到底是1还是0
if ( (n&num)==n){ // 当num在该位置为1 时,此时shit将这个位置数值减上1
shit -= n;
}
else{ // 当num在该位置不为1 时,此时shit将这个位置数值加上1
shit += n;
}
n <<=1; // 1 往左搓一个位置
}
return shit;
}
};
法二
class Solution {
public:
int findComplement(int num) {
long shit=(long)num;
long n=0;
while (num){ //这个其实就是循环一遍,得到num的位置数量,然后创建一个都是1的相同位置的二进制数n
num>>=1;
n<<=1;
n |=1;
}
return shit^n ; //然后取异或即可了
}
};
题461 汉明距离
class Solution {
public:
int hammingDistance(int x, int y) {
int number = 0;
while (x>0 || y>0){
if((x&1)^(y&1)){ //最低位置如果不同
number++; //加一
}
x>>=1;// 偏移最低位
y>>=1;// 偏移最低位
}
return number;
}
};
- 重点
s &= s - 1 //可以计算二进制中 1 的个数
题477 汉明距离总和
class Solution {
public:
int totalHammingDistance(vector<int>& nums) {
int n = nums.size(),number1=0,number0=0,result=0;
for (int i=0;i<32;i++){ // 32位,所有遍历三十二次
for (int j=0;j<n;j++){
if(nums[j]&1 == 1){ //如果为1
number1++;
}
else{ //否则
number0++;
}
nums[j]>>=1;
}
result+=number1 * number0;
number1=0;
number0=0;
cout << result<<endl;
}
return result;
}
};
法二
class Solution {
public:
bool hasAlternatingBits(int n) {
int prev = 2; //这边是用来记录前一个位置的大小,所以初始值不设成1或者0就行。
while (n != 0) {
int cur = n % 2; //循环取出每一位,第一步取模
if (cur == prev) {
return false;
}
prev = cur;
n /= 2;//循环取出每一位,第二步除以2,更新n
}
return true;
}
};
题405 数字转换为十六进制数 (关于负数的 处理相关)
整数类型都可以以补码保存,最高位表示符号位。0为正数,1为负数。
首先整数转成16进制的方法:
其实,每个数都是以补码形式保存,正数的补码是他自己。而负数则是它本身的值每位求反(最高位符号位除外),最后加一。
例如:整数 6 和 -6 。
6 二进制原码为: 0000 00000000 0000 0000 0000 0000 0110
-6 二进制原码为:1000 0000 00000000 0000 0000 0000 0110
6为正数,原码和补码相同所以6对应的补码是他自己
0000 0000 0000 0000 0000 0000 0000 0110
-6为负数,补码为原码的位取反再加一,符号位除外
-6补码为:1111 1111 11111111 1111 1111 1111 1001+1 =
1111 1111 1111 1111 1111 11111111 1010 转换为十六进制: 0xFFFFFFFA
所以,这边 -6的话可以直接让 6+2**32次方即可,即 (long long) 6 + (1ll << 32) ;
class Solution {
public:
string toHex(int num) {
// 十六进制数对应的 16 种字符
char s[] = "0123456789abcdef";
//cout << chr[1]<<endl;
// 加上 2^32 后会爆 int 型,所以要用 long long 存储
long long n = (num < 0) ? (long long)num + (1ll << 32) : num;
//cout << n<<endl;
// 特判 n = 0 的情况
if(n == 0) return "0";
// 结果字符串
string ret = "";
while(n) {
// 进制转换
ret = s[n % 16] + ret;
n /= 16;
}
return ret;
}
};
题400 第n位数字
class Solution {
public:
int findNthDigit(long long n) {
long long list[] = { 9, 90, 900, 9000, 90000, 900000, 9000000, 90000000, 900000000,9000000000 ,90000000000};
//--------------------------------------------------------------------------------
// n<9 直接返回即可
if (n <= 9) {
cout << n << endl;
return n;
}
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
// 这里num记录 n 之前有多少位数 ; num1记录 n 之前有多少个数 ; number+1记录 n 当前所处的位置的位数
long long num = 0, number = 0, label = 0, num1=0, num2 = 1;
while (label==0) {
num += list[number] * num2 ;
num1 += list[number];
num2++;
number++;
if (num+list[number] * num2 > n) {
label = 1;
}
}
cout << "num: " << num << endl;
cout << "num1: " << num1 << endl;
cout << number << endl;
//--------------------------------------------------------------------------------
long long x_1 = n - num;
long long x_2 = x_1 % (number + 1);
long long x_3 = x_1 / (number + 1);
long long x_4 = num1 + x_3;
//--------------------------------------------------------------------------------
// 看看是否需要转移到下一个数,如果要那么下一个数的位置就是求余的位置,否则就是当前倒数的余数的位置
long long result = 0;
if (x_2 > 0) {
long long x_5 = x_4 + 1;
string temp1 = to_string(x_5);
result = temp1[x_2-1] - '0';
}
else if (x_2 == 0) {
string temp2 = to_string(x_4);
result = temp2[temp2.size()-1] - '0';
}
//--------------------------------------------------------------------------------
cout << result << endl;
return result;
}
};