题目:输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
这是一道并不复杂的,很基础的题。但是通过这道题,我更深刻的了解到了:
- java对于整型数据的处理。
- 位运算巧妙。
作为一个编程菜鸟,看题之后,我就知道,利用位运算是最为恰当的方式,但是碍于对位运算不甚熟
悉,因此也望而却步,最后使用了笨笨的呆呆的方式。不过解题思路虽然呆头呆脑,但也正是这种呆头呆脑,让我学习了更多知识(这里绝对没有“不呆头呆脑就学习不到知识的意思😊”),所谓塞翁失马,焉知非福,也正是这个道理。
我呆头呆脑的方式😜: 完全模拟整数到二进制补码的过程
一大波僵尸代码:
public int NumberOf1(int n) {
int p=n; //思路:
int q=0; // 1. 当n==0,返回0;
int count=0; // 2. 当n>0,老实的求余数。
if(n==0) return 0; // 3. 当n<0,这里就复杂了,一句话就是模拟
else if(n>0){ // 一个负数从转为正数,到转为反码数,再
while(p>0){ // 到转为补数的笨过程。
q=p%2;
if(q==1) count++;
p/=2;
}
}else{
if(n==-2147483648) return 1;
p=-p;
int temp=1;
int cishu=31;
while(p>0){
q=p%2;
q= q==0?1+temp:temp;
if(q==0) {
temp=0;
}else if(q==1){
temp=0;
count++;
}else{
temp=1;
}
p/=2;
cishu--;
}
count=count+cishu+1;
}
return count;
}
大神解锁方式👏👏👏:一切都是位运算
其实位运算在这导题中另一个好处就是,对于整形数据的存储和运算本身就是使用的补码方式,因此不需要再去计较负数的补码到底是多少。
方式一:最牛叉的看这里!!!
下面这种方式是最牛逼的 非常简单高效,代码已经减少到不能再少了,太棒了!!! 位运算的魅力体现的淋漓尽致!!!
int NumberOf1(int n) {
int count=0;
while(n)
{
count++;
n=n&(n-1);
}
return count;
}
n&(n-1) ,就是它,一切的罪魁祸首。(n-1)将最右边的1 变为 0,后边的0 则便为1 ,再通过 与自身相或,其他位不变,这个1到右边所有位都将会变为0,如:
11100 减后 11011 & 11100 = 11000
方式二:
下面两种方式交之上一种老实些,两种方式区别不大,就像一个走后门,一个走前门。
具体思路分别打个例子就大概知道了,比如第一种:
第一次: 10011 & 00001 = 00001 count++;
第二次: 10011 & 00010 = 00010 count++;
第三次: 10011 & 00100 = 00000
第四次: 10011 & 01000 = 00000
第五次: 10011 & 10000 = 10000 count++;
class Solution {
public:
int NumberOf1(int n) {
int falg=1;
int count=0;
while(falg){
if(n&falg) count++;
falg=falg<<1;
}
return count;
}
};
public class Solution {
public int NumberOf1(int n) {
int a=0;
if(n==0)return 0;
while(n !=0){
if((n&1)>0){
a++;
}
n=n>>>1;
}
return a;
}
}
从本题中获得的对整型数据存储的深入理解
首先 int 类型是4个字节来装载,所以共32位,除开符号位有31位用于数据表达。
正数表达的范围:1~2^31-1 也就是 1~ 2 147 783 647
负数表达的范围:-1~-2^31-1 也就是-1~ -2 147 783 648
为什么差1呢? 问题出在 0 上。
因为 0 是作为正数存储的,因此正数加上0就是2147783648个数字。
而对负数就没有0 ,因此从-1存储到-2147783648,
这时对于补码 -1占的就是1111111111111111111111111111111
而-2147783648占的就是1000000000000000000000000000
具体个数别介意,意思意思就行😅