求栈中元素个数算法_程序员算法面试题之二进制中1的个数

本文参考书籍 《剑指offer》 作者何海涛

01 题目

请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如:9表示成二进制为1001,有两位是1,因此输入9该函数输出2。

02 相关知识点回顾

  • 与运算&: 1 & 1=1 , 1 & 0=0, 0 & 0=0
  • 或运算|: 1 | 1 = 1, 1 | 0 = 1 , 0 | 0=0
  • 非运算^: ^1=0 , ^0=1
  • 右移运算:(1)正数二进制右移运算,正数左边补充0,右边减少一位。

(2)负数二进制右移运算,左边补充1,右边减少一位。(计算机底层数值表示中第一位是符号位,用1表示负数,为了保持负数性质,右移左边补充1)

  • 原码,反码,补码:(1) 原码,某个数的二进制表示 (2)反码,原码符号位除外其他数值取反。如java里面的整型32位的最高位,其余31位取反 从0到1,或者从1到0。(3)补码=反码+1
  • 正数的原码,反码,补码完全相同,即都是自身。
  • 在计算机中,负数都是采用补码表示的。

03 解法1

将输入的数值和1进行与运算

if n&1 ==0 说明最后一位为0,if n&1 != 0 说明最后一位为1。

之后右移数值,去掉最右面的一位,循环判断。

结束条件 右移到n为0

ed3a4c8353c5160ce0eed641f041d56f.png

这种解法对于正数可以给出正确的答案,如果对于负数,则会造成死循环,如-1,它的计算机二进制(补码形式)表示为 1111 1111 1111 1111 1111 1111 1111 1111,那么右移一位左面补充为1,n永远不能为0

System.out.println(0b11111111111111111111111111111111);// 计算机表示的二进制-1

04 解法2

取变量flag=1进行左移,然后与数值进行&运算,如果不为0,说明该位为1,否则为0

4bea2b8b48d0fedf61213f25adc49158.png

结束条件:左移直到flag唯一的1被移没,此时flag==0 ,所以flag!=0为while循环条件

ebaaf8af043f167f4b26be87ecc24556.png

如果是int型数值,不管是数值为几,每次都移动32次结束循环

05 解法三

先说结论:n&n-1得到的值为n最后一位1变为0,所以每次通过n=n&(n-1)减少n中1的个数,直到n中1的个数为0,n == 0 结束循环。

推理过程:数值的二进制表示中,最后一位要么为1,要么为0

(1)最后一位为1,那么减1,就把最后一位的1变为0,此时与n 做与运算,结果除了最后一位变为0之外,其他位数值都不变。如 10011 & 10010=10010

f8688c33c63e73e9cf005b5fd65b5e63.png

(2)最后一位为0, 如11100, 减一之后,变为 11011 ,假设最右边的1的位置为m ,那么11100减1之后m位的1变为0,m位右边的0都变为1

109be41216aa7cba3a8404c8b228674e.png

所以 11100 & 11011=11000 把 最右面的一位1消掉。消掉多少个1就是这个n中总共有多少个1

7ffec61e2d262741269c01ec51f2b219.png

06 负数的结果

输入比如-1,结果是32,因为负数在计算机中以补码的形式表示,所以-1的二进制形式为

System.out.println(0b11111111111111111111111111111111);// 0b表示二进制

其他负数结果类似

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值