191.位1的个数
解题思路
使用位运算,利用左移右移的特性算,
优化:
利用规律:n&(n - 1),其运算结果恰为把 n 的二进制位中的最低位的 1 变为 0 之后的结果。
package leadcode;
/**
* @author : icehill
* @description : 位1的个数
* 编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 '1' 的个数
* 提示:
* 请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。
* 在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在上面的 示例 3 中,输入表示有符号整数 -3。
* 来源:力扣(LeetCode)
* 链接:https://leetcode-cn.com/problems/number-of-1-bits
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
* 解法:
* (1)使用位运算
* 1、<< :左移 左边最高位丢弃,右边补齐0
* 2、>> :右移 最高位是0,左边补齐0;最高为是1,左边补齐1
* 3、>>>:无符号右移 无论最高位是0还是1,左边补齐0
* 注意:
* 1、在对char、byte、short等类型的数进行移位操作前,编译器都会自动将数值转化为int类型,然后再进行操作
* 2、由于int类型变量只占4Byte字节(32bit)因此当位移位数超过32bit时,位移运算没有任何意义
* ,所以在Java语言中为了保证移动位数的有效性,以使右移的位数不超过32bit,采用了取余的操作,即a>>n等价于a>>(n%32)
* 时间复杂度:O(k),其中 k 是 int 型的二进制位数,k=32
* 空间复杂度:O(1),我们只需要常数的空间保存若干变量。
*
* (2)优化
* 观察这个运算:n&(n - 1),其运算结果恰为把 n 的二进制位中的最低位的 1 变为 0 之后的结果。
* 如:6&(6-1) = 4, 6 = (110)2, 4 = (100)2 运算结果 4 即为把 6 的二进制位中的最低位的 1 变为 0 之后的结果。
* 这样我们可以利用这个位运算的性质加速我们的检查过程,在实际代码中,我们不断让当前的 n 与 n−1 做与运算,
* 直到 n 变为 0 即可。因为每次运算会使得 n 的最低位的 1 被翻转,因此运算次数就等于 n 的二进制位中 1 的个数。
* 时间复杂度:O(logn)。循环次数等于 n 的二进制位中 1 的个数,最坏情况下 n 的二进制位全部为 1。我们需要循环 logn 次。
* 空间复杂度:O(1),我们只需要常数的空间保存若干变量。
* @date : 2021-04-18
*/
public class Solution191 {
public static void main(String[] args) {
Solution191 solution191 = new Solution191();
System.out.println(solution191.hammingWeight(-1));
System.out.println(solution191.hammingWeight(1));
System.out.println(solution191.hammingWeight(2));
System.out.println(solution191.hammingWeight(3));
System.out.println(solution191.hammingWeight(128));
}
/**
* 最优解法
* @param n
* @return
*/
public int hammingWeight(int n) {
int count = 0;
//6(110): 6&(6-1)= 110 & 101 =100,相当于把 n 的二进制位中的最低位的 1 变为 0的结果,循环知道n为0
//4(100)
while (n != 0) {
n = n & (n - 1);
count++;
}
return count;
}
/**
* 右移
* @param n
* @return
*/
public int hammingWeightOne(int n) {
int count = 0;
if (n < 0) {
count++;
}
int num = 31;
while (num-- > 0) {
if ((n & 1) == 1) {
count++;
}
n = n >> 1;
}
return count;
}
/**
* 左移,最高位丢弃,右边补0
* @param n
* @return
*/
public int hammingWeightTwo(int n) {
int ret = 0;
for (int i = 0; i < 32; i++) {
if ((n & (1 << i)) != 0) {
ret++;
}
}
return ret;
}
}