补充知识:位运算
- 基础与、或、异或运算
与(&) | 或(|) | 异或(^) |
---|---|---|
0&0=0 | 0|0=0 | 0^0=0 |
0&1=0 | 1|0=1 | 1^0=1 |
1&0=0 | 0|1=1 | 0^1=1 |
1&1=1 | 1|1=1 | 1^1=0 |
有0则0 | 有1则1 | 同出0不同出1 |
- 左移
左移n位最左边的n为直接丢弃,右边补n个0.
00001010<<2=00101000
- 右移
正数:直接右边n个0抛弃,左边补0;
负数:直接右边n个0抛弃,左边补上n个1;
00001010>>2=00000010
10001010>>3=11110001
题目描述
请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如把9表示成二进制是1001,有2位是1 因此如果输入9,该函数输出2;
解题思路
- 将正数和1做与运算,如果为1则记录加1(循环一次整数右移一次)。可能引起死循环。
- 将1来左移,如果与运算为1就记录加1,直到结果为0.。对于int这样的数据类型(32位 左移32次 因为int占4字节 也就是32位),移动次数太多,效率低。
- 将整数-1,再与原数据做与运算,运算一次消耗掉原数据一个1,直到为0截止。只需要循环n个1次。
算法图解
第二:
第三:
参考代码:
package offer;
/**
* 请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如把9表示成二进制是1001,有2位是1 因此如果输入9,该函数输出2;
*/
public class Offer15 {
public static void main(String[] args) {
int nums = 9;
System.out.println(NumBerOf1(nums));
// System.out.println(HNumBerOf1(nums));
}
// 可能引起死循环的解法1
public static int numberof1_1(int n) {
int count = 0;
while (n != 0) {
if ((n & 1) != 0) {
count++;
}
n = n >> 1;
}
return count;
}
/**
* 常规写法 将1 来左移 与原数据按位做与运算
* 32位 左移32次 因为int占4字节 也就是32位
*
* @param n
* @return
*/
static int NumBerOf1(int n) {
int count = 0;
int flag = 1;
while (flag != 0) {
System.out.println((n & flag));
if ((n & flag) != 0) {
count++;
}
flag = flag << 1;
}
return count;
}
/**
* 减1后与运算 直到等于0
* @param n
* @return
*/
static int HNumBerOf1(int n) {
int count = 0;
while (n != 0) {
++count;
n=(n-1)&n;
}
return count;
}
}
附录
该题源码在我的 ?Github 上面!