Python - 深夜数据结构与算法之 位运算

目录

一.引言

二.位运算简介

1.二进制与十进制

2.左/右移

3.位运算

4.异或 XOR

5.指定位置的位运算

6.实战要点

三.经典算法实战

1.Number-1-of-bits [191]

2.Power-Of-Two [231]

3.Reverse-2-Bits [190]

4.N-Queens [51]

四.总结


一.引言

通常情况下我们计数采取十进制,这是因为日常生活中我们习惯了 0-9 的数字习惯,而对于计算机而言,其通过 0-1 的二进制方式表示和存储数字。本节开始我们学习二进制以及其对应的位运算。

二.位运算简介

1.二进制与十进制

机器中数字的表示和存储格式就是二进制,给定数字 0101 其等于从后向前:

1 * 2^{0} + 0 * 2^{1} + 1 * 2^{2} + 0 * 2^{3} = 1 + 0 + 4 + 0 = 5

即对应位置的索引作为 2 的指数,对应位置的值作为指数幂的系数,累加即为 10 进制的数字。

相反的,如果想把一个 10 进制的数字转换为 2 进制,则我们依次除 2 取余,把得到的数字反转即可得到其二进制。这里不好理解的话可以对照着上面 10 进制转 2 进制的公式再思考思考。上面的图片来自: wikihow,是一个很好玩的百科网站,大家可以去搜索你想了解的内容。

2.左/右移

左移右移就是把当前二进制数字向左或向右移动一个位置,空出来的位置补 0 ,被顶出去的位置就不要了。我们老式的计算机一般是采用 32 位表示,而新的计算机则都采用了 64 位表示。

3.位运算

- 按位或  有一个 1,则或出来就是 1

- 按位与  有一个 0 ,则与出来就是 0 

- 按位取反 0 变成 1,1 变成 0 

- 按位异或   相同为 0,不同为 1

以上位运算都是在两个二进制数字之间展开。

4.异或 XOR

这里 1s 代表全为 1,即把 0 取反 ~0。 后面两条定律使用的比较少,前面四条性质比较常用。

5.指定位置的位运算

上面给出了一些位运算常见的位置操作,用于我们处理对应位置的位数。 

6.实战要点

判断奇偶以及 /2 的常规操作,我们都可以改写为位运算的方式提高效率,除此之外通过 & 方法可以得到清除、得到最低位 1 的操作。

三.经典算法实战

1.Number-1-of-bits [191]

位1的个数: https://leetcode.cn/problems/number-of-1-bits/description/

◆ 题目分析

& 操作是, 1 & x = x,所以我们可以遍历 32 位数的每一位 & 1 的值,如果为 1 则说明该位为 1,则 cnt += 1,或者使用上面实战要点中 X = X & (X-1) 清零最低位 1 的操作,能清几次代表有几个 1。

◆ 1 & x = x

class Solution(object):
    def hammingWeight(self, n):
        """
        :type n: int
        :rtype: int
        """
        cnt = 0

        for i in range(32):
            if n & (1 << i):
                cnt += 1
        
        return cnt

 ◆ x & (x-1) 

class Solution(object):
    def hammingWeight(self, n):
        """
        :type n: int
        :rtype: int
        """
        cnt = 0

        while n:
            n = n & (n-1)
            cnt += 1
        
        return cnt

 n & (n-1) 的示意图可以参考上面的过程。

2.Power-Of-Two [231]

2的幂: https://leetcode.cn/problems/power-of-two/description/

◆ 题目分析

套用上面的 1 bits 方法,由于2的幂次一定只有 1 位有 1,所以判断 cnt 是否为 1 即可。也可以一直 % 2 并 / 2,看能不能一直除下去。

◆ x & (x-1)

class Solution(object):

    def isPowerOfTwo(self, n):
        """
        :type n: int
        :rtype: bool
        """
        if n == 0:
            return False

        return n & (n-1) == 0

◆ x % 2 - x / 2

class Solution(object):

    def isPowerOfTwo(self, n):
        """
        :type n: int
        :rtype: bool
        """
        if n == 1:
            return True
        
        if n <= 0 or n % 2:
            return False
        
        return self.isPowerOfTwo(n / 2)

3.Reverse-2-Bits [190]

颠倒 2 进制: https://leetcode.cn/problems/reverse-bits/description/ 

◆ 题目分析

把 n 的 32 位,每一位拿出来再往后追加,类似于一位一位 reverse。

◆ x << 1

class Solution:
    # @param n, an integer
    # @return an integer
    def reverseBits(self, n):
        res = 0
        for i in range(32):
            # 有 1 就 1,没 1 就 0
            res = (res << 1) | (n & 1)
            n >>= 1
        return res

res << 1: 把最后一位空出来

n & 1: 0 是 0、1 是 1

|: 前面 res 部分不动,后面 0 是 0、1 是 1 

通过这三部分实现反转与追加。 

4.N-Queens [51]

N 皇后: https://leetcode.cn/problems/n-queens/description/ 

◆ 题目分析

老生常谈的问题了, 传统的办法我们是构造了 pie、na、row 三个 set 进行去重,学习了位运算后,我们也可以将棋盘按 45 度划分 2n-1 个对角线,这样 pie、na 就只需要位运算判重而不需要 set 了,提高了空间利用率和时间效率。

◆ DFS + Set

class Solution(object):
    def solveNQueens(self, n):
        """
        :type n: int
        :rtype: List[List[str]]
        """

        results = []
        # 行 左 右 是否可以放置
        cols = set()
        pie = set()
        na = set()

        def dfs(n, row, cur):
            if row >= n:
                results.append(cur)
            
            for col in range(n):
                if col in cols or (row + col) in pie or (row - col) in na:
                    continue
                
                # 判断有效
                cols.add(col)
                pie.add(row + col)
                na.add(row - col)

                dfs(n, row + 1, cur + [col])

                # 恢复状态
                cols.remove(col)
                pie.remove(row + col)
                na.remove(row - col)
        
        dfs(n, 0, [])
        return self.genResult(n, results)

    def genResult(self, n, results):
        return [[ '.' * i + 'Q' + (n - i - 1) * '.' for i in result] for result in results]

    def genResultV2(self, n, results):
        re = []
        for result in results:
            re.append([ '.' * i + 'Q' + (n - i - 1) * '.' for i in result])
        return re

◆ DFS + Simple Set

class Solution(object):
    def solveNQueens(self, n):
        """
        :type n: int
        :rtype: List[List[str]]
        """

        results = []

        def dfs(queue, diff, total):

            row = len(queue)
            if row == n:
                results.append(queue)
                return None
            
            for col in range(n):
                if col not in queue and row + col not in total and row - col not in diff:
                    dfs(queue + [col], diff + [row - col], total + [row + col])

        dfs([], [], [])
        return [[ '.' * i + 'Q' + (n - i - 1) * '.' for i in result] for result in results]


◆ DFS + Bit

class Solution(object):

    def power_of_two(self, num):
        power = 0
        while num % 2 == 0:
            power += 1
            num = num / 2
        return power

    def solveNQueens(self, n):
        """
        :type n: int
        :rtype: List[List[str]]
        """
        if n < 1:
            return []

        results = []

        def DFS(n, row, cols, pie, na, cur):
            if row >= n:
                results.append(cur)
                return

            # 得到当前所有空位
            bits = (~(cols | pie | na) & ((1 << n) - 1))

            while bits:
                p = bits & -bits  # 取最低位的 1
                bits = bits & (bits - 1)  # P 位置放置皇后
                DFS(n, row + 1, cols | p, (pie | p) << 1, (na | p) >> 1, cur + [p])

        DFS(n, 0, 0, 0, 0, [])

        return [['.' * self.power_of_two(i) + 'Q' + (n - self.power_of_two(i) - 1) * '.' for i in result] for result in results]

这里 bits 以及一些递进的操作直接看容易懵,大家可以在 n=4 的情况下,打印每一次运算的 2 进制,感受下如何通过位运算求解,这里可以通过 bin() 方法获取二进制表示。

四.总结

位运算的解法和题目相对来说比较抽象,不理解的时候还是多转换为 2 进制数字,查看其演进的过程,更好的熟悉其推导过程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/325070.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RequestResponse

1.Request 请求 作用:使用Request对象来获取请求数据 1.Request获取请求数据的方法 2.通用方式获取请求参数 3.POST请求参数中文乱码解决 4.请求转发 概念: 一种在服务器内部的资源跳转方式 2.Response 响应 作用:使用response对象设置响应数据 1.Response设置响应数据功能 …

【Emgu.CV教程】5.3、几何变换之金字塔变换

这一段文字描述来自百度百科&#xff1a; 图像金字塔是图像多尺度表达的一种&#xff0c;是一种以多分辨率来解释图像的有效但概念简单的结构。一幅图像的图像金字塔是一系列以金字塔形状&#xff08;自下而上&#xff09;逐步降低&#xff0c;且来源于同一张原始图的图像分辨率…

OpenCV-25sobel算子(索贝尔算子)

前面所提到的滤波都是用于降噪的&#xff0c;去掉噪声&#xff0c;而算子是用来找边界&#xff0c;来识别图像的边缘。 一、概念 边缘是像素值发生跃迁的值&#xff0c;是图像的显著特点之一&#xff0c;在图像特征提取&#xff0c;对象检测&#xff0c;模式识别等方面都有重…

数据结构与算法教程,数据结构C语言版教程!(第四部分、字符串,数据结构中的串存储结构)二

第四部分、字符串&#xff0c;数据结构中的串存储结构 串存储结构&#xff0c;也就是存储字符串的数据结构。 很明显&#xff0c;字符串之间的逻辑关系也是“一对一”&#xff0c;用线性表的思维不难想出&#xff0c;串存储结构也有顺序存储和链式存储。 提到字符串&#xff…

Java 日志体系泣血总结

目录 一. 前言 二. Log 日志体系 2.1. 背景/发展史 2.2. 关系/依赖 2.2.1. JCL&#xff08;Jakarta Commons Logging&#xff09; 2.2.2. SLF4J 2.2.3. SLF4J 的适配 2.2.4. Spring 统一输出 三. 总结 一. 前言 本文的目的是搞清楚 Java 中各种日志 Log 之间是怎样的关…

spring boot mybatis-plus dynamic-datasource 配置文件 相关依赖环境配置

spring boot mybatis-plus dynamic-datasource 配置文件 相关依赖环境配置 ##yaml配置 server:port: 8866servlet:context-path: /yymtomcat:max-threads: 300connection-timeout: 57000max-connections: 500connection-timeout: 57000 spring:datasource:dynamic:primary: m…

MyBatis 查询数据库

一. MyBatis 框架的搭建 本篇所用sql 表: drop table if exists userinfo; create table userinfo(id int primary key auto_increment,username varchar(100) not null,password varchar(32) not null,photo varchar(500) default ,createtime timestamp default current_tim…

SpringBoot 全局异常统一处理:BindException(绑定异常)

概述 在Spring Boot应用中&#xff0c;数据绑定是一个至关重要的环节&#xff0c;它负责将HTTP请求中的参数映射到控制器方法的入参对象上。在这个过程中如果遇到任何问题&#xff0c;如参数缺失、类型不匹配或验证失败等&#xff0c;Spring MVC将会抛出一个org.springframewo…

Hive 数据迁移

一、需求 同步集团的数据到断直连环境。 二、思路 三、同步数据&#xff08;方案&#xff09; 1、环境&#xff1a;断直连模拟环境 2、操作机器&#xff1a;ETL 机器 XX.14.36.216 3、工作路径&#xff1a;cd /usr/local/fqlhadoop/hadoop/bin 4、执行命令&#xff1a; 命令…

python 元组的详细用法

当前版本&#xff1a; Python 3.8.4 文章目录如下 1. 介绍元组 2. 定义元组 3. 访问元组 4. 查询元组 1. 介绍元组 元组&#xff08;Tuple&#xff09;是一个有序的、不可变的数据序列。它可以包含各种类型的数据&#xff0c;例如数字、字符串、列表等。元组使用圆括号()来…

书生·浦语大模型实战营第四节课笔记及作业

XTuner 大模型单卡低成本微调实战 1 Finetune简介 大语言模型LLM是在海量的文本内容基础上&#xff0c;以无监督或半监督方式进行训练的。海量的文本内容赋予了大模型各种各样的行业知识。但是如果直接把大模型的知识用于生产实践&#xff0c;会发现回答不大满意。微调的目的…

【RL】(task1)绪论、马尔科夫过程、动态规划、DQN(更新中)

note 文章目录 note一、马尔科夫过程二、动态规划DQN算法时间安排Reference 一、马尔科夫过程 递归结构形式的贝尔曼方程计算给定状态下的预期回报&#xff0c;这样的方式使得用逐步迭代的方法就能逼近真实的状态/行动值。 有了Bellman equation就可以计算价值函数了马尔科夫过…

微服务架构设计核心理论:掌握微服务设计精髓

文章目录 一、微服务与服务治理1、概述2、Two Pizza原则和微服务团队3、主链路规划4、服务治理和微服务生命周期5、微服务架构的网络层搭建6、微服务架构的部署结构7、面试题 二、配置中心1、为什么要配置中心2、配置中心高可用思考 三、服务监控1、业务埋点的技术选型2、用户行…

Burp Suite如何拦截站点请求

Burp Suite是一款强大的Web渗透测试工具&#xff0c;可以用于拦截、修改和分析Web应用程序的请求和响应。要使用Burp Suite拦截站点请求有两个方案。我会倾向选用方案二&#xff0c;因为它不会影响本地电脑代理配置。 1. 方案一 安装Burp Suite&#xff1a;首先&#xff0c;您…

【C语言】ipoib驱动 - ipoib_cm_post_receive_nonsrq_rss函数

一、ipoib_cm_post_receive_nonsrq_rss函数定义 static int ipoib_cm_post_receive_nonsrq_rss(struct net_device *dev,struct ipoib_cm_rx *rx, int id) {struct ipoib_dev_priv *priv ipoib_priv(dev);struct ipoib_recv_ring *recv_ring priv->recv_ring rx->ind…

提升开发效率的google插件

在如今的软件开发领域&#xff0c;Google Chrome浏览器的开发者插件扮演着至关重要的角色&#xff0c;为开发人员提供了丰富的工具和功能&#xff0c;从而提高了开发效率。下面介绍几款强大的 Google 插件&#xff0c;它们在不同方面为开发者提供了便利&#xff0c;并能显著提升…

力扣每日一题--2088. 统计农场中肥沃金字塔的数目

看到这道题有些人很容易放弃&#xff0c;其实这道题不是很难&#xff0c;主要是题目长&#xff0c;读的容易让人放弃&#xff0c;但是 只要抓住一些性质就可以解决该问题。 本题中的定义放到图像里其实就是个金字塔&#xff0c;下层的那部分比上一层的那部分&#xff0c;长度加…

51单片机HC-SR04超声波测距lcd1602显示(程序+ad硬件设计+文档说明)

本帖主控使用STC89C52单片机&#xff0c;超声波测距采用HC-SR04模块&#xff0c;包含ad硬件设计和文档。 测距原理 超声波测距是通过不断检测超声波发射后遇到障碍物所反射的回波&#xff0c;从而测出发射和接收回波的时间差t,然后求出距SCt/2,式中的C为超声波波速。由于超声…

【GitHub】如何删除GitHub仓库里的文件夹(区分 rm/git rm)

删除GitHub仓库里的一个文件夹 1、复制仓库地址2、在本地新建一个空文件夹3、在空文件夹内&#xff0c;右键选择Git Bash Here4、弹出GIT Bash框5、克隆远程仓库6、拉取远程仓库7、查看仓库里的文件8、选择想要删除的文件夹进行删除9、提交删除说明10、更新GitHub远程仓库 在gi…

微信小程序-----wxss模版样式

目录 前言 一、WXSS 1. 什么是 WXSS 2. WXSS 和 CSS 的关系 二、rpx 1. 什么是 rpx 尺寸单位 2. rpx 的实现原理 3. rpx 与 px 之间的单位换算 三、样式导入 1. 什么是样式导入 2. import 的语法格式 四、全局样式和局部样式 1. 全局样式 2. 局部样式 前言 上一期…