目录
acwing-801二进制中1的个数
暴力解法
在学习位运算算法之前,我采用了算是比较直接得办法吧,自然也时间复杂度高。下面说一下我看到的思路和做题过程。
我最开始想着在之前学c语言的时候,依稀记得printf有进制转换的输出格式,想着直接这样转化的话不就看到了每个数的二进制表示,再遍历每一个数,记录1的个数即可。
关于printf函数输出数据进制转换之后的结果,就像下面这样
int num = 35;
printf("%05o\n", num); // 输出八进制数,保留5位,高位补零
printf("%03d\n", num); // 输出十进制数,保留3位,高位补零
printf("%05x\n", num); // 输出十六进制数,保留5位,高位补零
后来发现由于printf函数是一个输出函数,我们没办法直接保存下printf的输出结果,后面的就没法进行了。这个思路就pass掉了。
不过复习了一下printf的转换数制输出还是挺好的。
还是按照上面的思路,就是我们要考虑如何将一个十进制数转化为二进制了。刚好本网工专业本学期学了数字逻辑(最近又在期末预习ddddhh),里面有进制转换的内容,回顾一下啦hh
ps:这里关于进制转换数字逻辑课程里有很多包括其他进制之间的各种转换.(b站期末速成课里讲的很清楚hhh)这里附上相关章节的课程链接,有需要的朋友自取啦~(从第一课时开始前后几个视频都是讲进制转换哒)对啦,里面也包含原反补码的介绍,前几个视频可以看看。
http://www.bilibili.com/video/BV1H54y1k7kM?p=2&vd_source=02dfd57080e8f31bc9c4a323c13dd49c
那么根据图中,我们进行手算进制转换的过程,将其转化为代码呈现即可。这里思路还是比较简单的。
代码如下
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
int a[N],n;
string Binary(int a)
{
string b;
int k=0;
while(a)
{
b+='0'+a%2;
a /= 2;
}
/*由于我们是将余数从下往上写的二进制数
直接向上面这样的话b字符串应该是我们看着是其正方向的二进制表示
reverse(b.begin(),b.end());
后来想想这段代码其实不要也行,这道题目没有关于这方面的要求
因为不管是正向存储还是逆向存储都不会影响其二进制表示中1的个数*/
return b;
}
int main()
{
string b;//存储当前数字的二进制
int sum=0;//存储当前数字二进制中1的个数
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
b=Binary(a[i]);
for(int j=0;j<b.size();j++)
{
if(b[j]=='1')sum++;
}
a[i]=sum;//由于原数组在后面也没在用到,可以直接改值
sum=0;//这里一定要注意将sum重置为0
}
for(int i=0;i<n;i++)
{
cout<<a[i]<<" ";
}
return 0;
}
必要的注释都写在代码里了。应该很容易理解。
进制转换
在写这个进制转换的时候突然想起之前写过十六进制转十进制的代码。之前是用c写的
#include<stdio.h>
#include<string.h>
int trans(char arr[],int len)
{
int i,sum=0,num=0;
int k=len;
for(i=0;i<len;i++)
{
if(arr[i]>='A'&&arr[i]<='F')
{
num=arr[i]-55;
}
else
{
num=arr[i]-48;
}
//单独看十六进制数的每一位
int t=k;//根据数组长度确定是乘以几次方
while(t-1)
{
num*=16;
t--;
}
if(k-1==0)//如果只有一位数,是乘以零次方,所以还是其本身
{
num=num;
}
k--;
sum+=num;
}
return sum;
}
int main()
{
//写一个函数,输入一个十六进制数,输出相应的十进制数
char sixteen[100];
int ten,len;
scanf("%s",sixteen);
len=strlen(sixteen);
ten=trans(sixteen,len);
printf("%d",ten);
return 0;
}
其实思路都是按照我们手算进制转换的方法。忘记的可以看前面提到的教程哦。
位运算
这道题就是位运算的其中一个主要应用。
lowbit(x)-----返回x的最后一位二进制1是多少
利用位运算 x&(-x)
代码应用
#include<iostream>
using namespace std;
int main()
{
int a;
cin>>a;
int ans=a&(-a);
cout<<ans<<endl;
return 0;
}
这里输出的就是最后一个1所对应的二进制里的值。
刚好这里引申出我们这道题:求1的总数的思路。就是我们每次吧其最后一个1去掉,删去了多少次,就是有多少个1.
本题代码如下
#include<iostream>
using namespace std;
const int N=1e5+10;
int lowbit(int x)
{
return x&(-x);
}
int main()
{
int n;
cin>>n;
while(n--)
{
int x;
cin>>x;
int sum=0;
while(x)
{
x-=lowbit(x);//在整个二进制数里吧这个最后一个1的值减去
sum++;
}
cout<<sum<<" ";
}
return 0;
}
求某个数第k位二进制数是几
位运算另一个应用就是--求某个数第k位二进制数是几
位运算符,如位与(&)、位或(|)、位非(~)、位异或(^)、左移(<<)和右移(>>),都是直接对整数的二进制位进行操作。
我们这里的操作主要用的是右移运算符">>",表示将该二进制数每一位都开始向后移动,比如1110,>>2,就变成了 11 (前面用零填充),当我们将一个二进制数与1进行位与操作时,我们实际上是在检查该数字的最右边的位(也就是第0位/注意从0开始算哦)是否为1。如果是,那么结果就是1,否则结果就是0。
关于这里做一些解释(因为我刚开始没明白hh)。
我们将二进制数与 1 进行与操作,1 的二进制表示只有最有一个数字是 1 ,前面可以按照该二进制数的位数进行补零。那 1 的二进制数前面都是 0 ,与出来肯定也都是 0 ,所以我们说 将一个二进制数与1进行位与操作时,我们实际上是在检查该数字的最右边的位(也就是第0位)是否为1。可以理解哈。
需要注意的就是我们k表示第几位二进制数,由于二进制从0开始计数,就是下标从0开始,所以我们输入4,就是第五位这样。
代码应用
#include<iostream>
using namespace std;
int main()
{
int a,k;//k表示第几位,位数从0开始计算
cin>>a>>k;
int ans=(a>>k)&1;
cout<<ans<<endl;
return 0;
}
好啦,位运算就先说到这里啦。
如果哪里说法有问题欢迎指出,非常感谢!!
也欢迎交流和建议哦!