目录

二进制的表示

二进制的位操作

应用: 剑指offer15.统计二进制中1的个数(多种方法,位右移操作、与操作等)


转自:https://www.jianshu.com/p/3a31065a8e58

红色为自己添加

我们都知道在计算机中所有的信息最终都是以二进制的0和1来表示,而有些算法是通过操作bit位来进行运算的,这就需要我们了解Python中如何去表示二进制,又如何是进行位运算的。

二进制的表示

0b111 类型是整型,一般为二进制32整型或者16整型,常见的是二进制8位整型

bin(n)可以将一个十进制或者其他进制的整型转化成二进制,返回的类型是字符串表示的二进制整型

n = 0b101
print(type(n))
print(type(bin(n)))

<class 'int'>
<class 'str'>

首先在Python中可以通过以"0b"或者"-0b"开头的字符串来表示二进制,如下所示

print 0b101 # 输出5
print 0b10  # 输出2
print 0b111 # 输出7
print -0b101 # 输出-5

由此可知我们用二进制表示的数字在打印之后会变成我们更为熟悉的十进制数,更容易被人理解。
当我们需要看十进制数字的二进制表示时,可以使用bin函数

bin(5)  # 输出0b101

二进制的位操作

首先一点需要明确的是所有的运算(包括位操作)在计算机内部都是通过补码形式来进行运算的,关于补码可以参考文章原码,反码和补码,计算机内部运算示意图如下:


此部分转自:https://blog.csdn.net/weixin_39671935/article/details/113980497

先简单说一些概念:

原码:从符号位开始表示,1是正数,0是负数

反码:正数的原码反码补码都是一样的。

负数的反码是在其原码的基础上, 符号位不变,其余各个位取反

比如-5转成二进制原码1101,在算出反码1010

补码:正数的原码反码补码都是一样的。

负数的补码是反码+1


在Python中提供了如下二进制的位操作:

>>  #右移
<<  #左移
|   #位或
&   #位与
^   #位异或
~   #非

下面我们分别来看下:

左移

0b11 << 2   #输出为12, 即0b1100
5 << 2      #输出为20, 即0b10100
-2 << 2     #输出为-8
5 << 64     #输出为92233720368547758080L
  1. 以0b11为例,0b11的补码就是0b11,所以左移就是将所有的0和1的位置进行左移,移位之后将空位补0。
  2. 负数的左移相对来说就比较复杂,以-2 << 2为例,-2的原码是10000000000000000000000000000010(32位系统),其补码为11111111111111111111111111111110,左移之后变为11111111111111111111111111111000,再转化为原码即10000000000000000000000000001000,也就是-8,也就是-2*(2**2)=-8
  3. 左移超过32位或者64位(根据系统的不同)自动转化为long类型。
  4. 左移操作相当于乘以2**n,以5 << 3为例,相当于5(2*3),结果为40。

右移

0b11 >> 1   #输出为1, 即0b1
5 >> 1      #输出为2,即0b10
-8 >> 3     #输出为-1
  1. 在Python中如果符号位为0,则右移后高位补0,如果符号位为1,则高位补1;
  2. 同样需要先转化为补码再进行计算,以-8 >> 3为例,-8的原码为10...01000,相应的补码为11...11000,右移后变为1...1,相应的原码为10...01,即-1。
  3. 右移操作相当于除以2**n,8 >> 3相当于8/(2**3)=1

0b110 | 0b101   #输出7,即0b111
-0b001 | 0b101  #输出-1

同样是转化为补码后再进行或运算, 只要有一位有1就为1。
所以或运算常常用于mask技术中的打开开关,即针对某一位把其置为1
比如将某个数字的第三位置为1,我们可以将mask设置为0b100,然后再或运算

mask = 0b100
0b110000 | mask  #turn on bit 3

0b110 & 0b011   #输出2,即0b010

与运算常常用于mask技术的关闭开关,即针对某一位把其置为0

mask = 0b10
0b111111 & mask  #turn off bit 2

异或

0b111 ^ 0b111   #输出0
0b100 ^ 0b111   #输出3

异或常用于将所有的位反转

0b1010 ^ 0b1111  #输出5,即0b0101

~0b101  #输出2,即0b010
~-3     #输出2

非运算就是把0变1,1变0,唯一需要注意的是取非时符号位也会变换,比如-3,原码是10...011,补码是11...101,取非后变为00...010,由于符号位为0,所以对应的原码即为其本身,即2。

二进制的减法:

设n=0b1010

则n-1=0b1001

减法原则和十进制的减法一致,只是向前借一的时候,一表示的不是10而是2,加法也是一样,满2进1

0 b 1 0 1 0
-         1
          =
0 b 1 0 0 1

应用: 剑指offer15.统计二进制中1的个数(多种方法,位右移操作、与操作等)

请实现一个函数,输入一个整数(以二进制串形式),输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。

示例 1:

输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。

示例 2:

输入:00000000000000000000000010000000
输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。

代码实现:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2021/5/17 17:59
# @Author  : @linlianqin
# @Site    :
# @File    : 剑指 Offer 15. 二进制中1的个数.py
# @Software: PyCharm
# @description:
'''
请实现一个函数,输入一个整数(以二进制串形式),输出该数二进制表示中 1 的个数。
例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。
''''''
思路:将n变成二进制形式,然后计数'1'的个数
'''
class Solution:def hammingWeight(self, n: int) -> int:return bin(n).count('1')# 将其转化为列表后再诸位变成整数进行相加def hammingWeight1(self,n):return sum(map(int,bin(n)[2:]))n = 0b101
print(Solution().hammingWeight(n))
print(Solution().hammingWeight1(n))# 优化思路,充分利用二进制的位操作
def hammingWeight2(n):# 这里诸位将二进制的数字和1进行运算,若结果为1,则说明当前位置值为1,否则为0count = 0while n: # 当n不全为0时count += n&1 # 这里是进行位与操作,这里的与操作默认是从高位开始的,因此需要进行右移n >>= 1return count
print(hammingWeight2(n))#优化,上述方法进行的是诸位运算,还可以继续优化,巧妙的利用n&n-1,二进制的减法和十进制一样,因此能够检测出最低位的1,即n-1
# n-1会使得最低位的1及后面的0发生变换,1-0,0-1,然后利用n&n-1来更新n,这样来达到计数效果
def hammingWeight3(n):count = 0while n:count += 1n &= n-1return count
print(hammingWeight3(n))
print(type(n))
print(type(bin(n)))

2
2
2
2
<class 'int'>
<class 'str'>

【剑指offer15.二进制中1的个数】——位操作(左移右移等)相关推荐

  1. 剑指offer 二进制中1的个数

    题目描述 输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. 解决方案: public class Solution {public int NumberOf1(int n) {int ...

  2. 剑指offer——二进制中1的个数(c++)

    题目描述 实现一个函数,输入一个整数,输出该数二进制表示中1的个数. 例如,把9表示成二进制是1001,则输出为2 常规解法 首先把n和1做位运算,判断n的最低位是不是1,然后把1左移一位得到2,再把 ...

  3. 【LeetCode笔记】剑指 Offer 15-. 二进制中1的个数 (Java、位运算)

    文章目录 题目描述 思路 & 代码 二刷 题目描述 涉及二进制,位运算跑不了- 思路 & 代码 既然是32位,那么通过一次遍历,每次判断一个位是否为1即可 public class S ...

  4. 《剑指offer》c++版本 15.二进制中1的个数

    如题: 平常开发过程中,遇到求数的每位数字的时候,通常做法是将这个逐位右移,本题目计算整数的二进制中1的个数,通过右移的方式,能够解决部分问题,但是,这里有个坑,如果整数为负的话,右移后最左边还是1, ...

  5. 面试题10-二进制中1的个数

    思路: 把一个整数和他减1后的数做位于运算,得到的结果(以10进制的整数给出)相当于把原整数的二进制表示中最右端的1变为0,很多问题都可以这么解决. 2的幂 乘2 除2 2的幂指数次放都可以转化为该数 ...

  6. 《LeetCode力扣练习》剑指 Offer 15. 二进制中1的个数 Java

    <LeetCode力扣练习>剑指 Offer 15. 二进制中1的个数 Java 一.资源 题目: 编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 ...

  7. [剑指Offer]12.二进制中1的个数

    题目 输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. 思路 把一个整数减去1,再和原整数做与运算,会把整数最右边一个1变成0.那么一个整数的二进制表示中有多少个1,就可以进行多次这样 ...

  8. 剑指Offer #11 二进制中1的个数(想不到的骚操作)

    题目来源:牛客网-剑指Offer专题 题目地址:二进制中1的个数 题目描述 输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. 题目解析 对于这种涉及位运算的题目,我们首先要了解基本的位 ...

  9. 《剑指offer》-- 把数组排成最小的数、丑数、二进制中1的个数、表示数值的字符串、替换空格

    一.把数组排成最小的数: 1.题目: 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个.例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为 ...

最新文章

  1. 报表统计-mysql存储过程
  2. 如何避免操作系统中多线程资源竞争的互斥与同步?
  3. 算法之最近最少使用LRU
  4. 【BZOJ 3160】 3160: 万径人踪灭 (FFT)
  5. linux下增加磁盘改变指定文件路径分区挂载点和迁移数据
  6. 深入理解计算机操作系统(一)
  7. callapplybind的js实现以及应用
  8. HTML文件上传与下载
  9. 了解java.nio.file.Path – 1
  10. 【大学物理】毕奥萨伐尔定律
  11. Ubuntu 12/14 个性化配置
  12. linux路由内核实现分析(四)---路由缓存机制(3)
  13. thinkphp 随机取10条数据_spark调优-数据倾斜
  14. 计算机 管理策略,有关管理组策略管理模板的建议 (.adm) 文件
  15. 网络口碑Market,生来“苟且”?
  16. “诱饵效应”让用户产生“冲突”营销心理学十大效应 营销值得学
  17. python分析谷歌浏览器的历史记录
  18. 地产中介门店10用户桌面云方案
  19. 单片机ESD静电防护总结
  20. win11动手学深度学习安装过程(GPU版)( CUDA Anaconda Mxnet )

热门文章

  1. SAM4E单片机之旅——13、LCD之ASF初步
  2. 猴子吃桃问题(南阳ACM324)
  3. window.parent和window.opener区别
  4. 推荐十款非常优秀的 HTML5 在线设计工具
  5. VUE组件 之 Drawer 抽屉
  6. vue-resource全攻略
  7. MySQL触发器(转载)
  8. scrapy 让指定的spider执行指定的pipeline
  9. UNION ALL returning wrong results?
  10. 【转载】网络流和最小费用流