如何统计一个数字x中1的个数
提示:异或运算重要知识点系列文章
只要了解异或运算的根本知识点,解决这些问题也就不在话下。
(1)认识异或运算的本质与基本规律,0^x=x,x异或x=0,有交换律,结合律,与顺序无关
(2)数组arr中,有一个数k出现了奇数次,其他数出现偶数次,请找到并打印这个数k
(3)如何把一个数字x最右侧那个1拿出来,变成00…10…的格式
题目
如何统计一个数字x中1的个数
一、审题
示例:x=11
x=1011
其中1的个数为3个
二、解题
暴力解
你可以这么玩,将x转化为字符数组
挨个统计完事
这会o(n)复杂度,还是那句话,N太大,就失效了。
异或运算最优解
既然又是涉及一个数字的操作,而且又是其中一个位的数,那么考虑一下用位运算,速度就要快很多!
前面我们学过,如何快速获取数字中最右侧那个1
rightOne = x&(x取反+1)
那我这么想:
如果x!=0,循环干:
(1)每次都获取最右侧那个1,让count++计数
(2)然后将x^rightOne,抹掉刚刚那个最右侧的1;(用的就是异或运算的特性)
(3)直到x为0再也没有1了,统计也就结束了
看例子:
x=1011
每次统计最右侧那个1,然后将其抹掉,这就是异或运算的好处。
获取最右侧那个1是异或公式来的(rightOne = x&(x取反+1))
抹掉它也是异或运算
可见异或运算的妙处!!
因此,快速就将1统计出来了。
手撕代码:
//统计某个二进制数N中的1的个数,这个也是利用上面最右边数字为1的原理
//先找一个最右边的1出来,然后计数,之后把N中最右边那个1抹除,然后继续统计
public static void countNof1(){
int N = 2;
int count = 0;//计数器
while (N != 0){//在N的1没有被完全抹除之前,继续统计1,并抹除最右边的1
int rightOne = N & ((~N) + 1);//找当前最右边那个1
count++;
N ^= rightOne;//用异或抹掉最右边的1,而不是&,这个不要混淆了
}
System.out.println(count);
}
总结
提示:重要经验:
1)获取最右侧那个1是异或公式来的(rightOne = x&(x取反+1)),抹掉它也是异或运算,可见异或运算的重要性
2)开头的几篇关于异或运算的重要知识点,一定要熟悉掌握。