算法通关村第十一关白银挑战——位运算符的高频算法题

大家好,我是怒码少年小码。

今天讲讲几个位运算的经典算法。

位移的妙用

1. 位1的个数

LeetCode 191:编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 ‘1’ 的个数。

  • 输入:n = 00000000000000000000000000001011
  • 输出:3
  • 解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 ‘1’。
方法一

还记得我们上一篇()最后写的位运算代码套路的获取吗?与运算的特点是只有两边都为1结果才为1,否则结果为零。利用这个特点我们可以解决这个问题,例如数字3和数字1的二进制串进行与运算:

00000000000000000000000000001011
& 00000000000000000000000000000001
= 00000000000000000000000000000001

只用我们把1左移或者把原始数字右移然后进行与运算,结果为1说明这一位上是1,就记录“1”的数量加1,知道把32为都比较完后,有多少个记录就可以了。原始数字右移的代码如下:

int hammingWeight(int n) {int count = 0;for (int i = 0; i < 32; i++) {count += (n >> i) & 1;}return count;
}
方法二:

按位与运算有个性质:对于整数n,计算n & (n-1)的结果为将n的二进制表示的最后一个1变成0。利用这条性质,令n = n & (n-1),则n最后的二进制表示中的1数量减少一个。例如:

重复该操作,直到n的二进制表示中的全部数位都变成0,则操作次数即为n的位1的个数。代码如下:

int hammingWeight01(int n) {int count = 0;while (n != 0) {n = n & (n - 1);count++;}return count;
}

这两种方法,第一种的循环次数取决于原始数字的位数,第二种取决于原始数字种"1"的个数,效率自然高不少。

###2. 比特位计数

LeetCode 338:给你一个整数 n ,对于 0 <= i <= n 中的每个 i ,计算其二进制表示中 1 的个数 ,返回一个长度为 n + 1 的数组 ans 作为答案。

  • 输入:n = 2
  • 输出:[0,1,1]
  • 解释:
    0 --> 0
    1 --> 1
    2 --> 10

自己先思考一下这题真的很简单!!

分析:遍历0 <= i <= n中的每一个数字,获取它们二进制串中的“1”的个数(可以单独设置一个函数),然后把个数保存到数组对应的位置上。

    int helper(int n){int count = 0;while(n != 0){n = n & (n-1);count++;}return count;}vector<int> countBits(int n) {vector<int> ans(n+1);for(int i =0; i < n+1; i++){int count = helper(i);ans[i] = count;}return ans;}

这就是一通百通吧😎。

3. 颠倒无符号整数

LeetCode 190:颠倒给定的 32 位无符号整数的二进制位。

颠倒二进制位

分析:肯定是先要获取某一位,然后再把它放到应该的位置上去。获取就用原始数字与1进行与运算,然后原始数字右移,这样我们就能得到低位置上的二进制数,然后通过左移power个来放到高位

 int reverseBits(int n) {int reversed = 0, power = 31;while (n != 0) {reversed += (n & 1) << power;n >>=1;power--;}return reversed;
}

n >>= 1是一个右移操作符,它将变量n的值向右移动一位。类似于n+=1是把n的值加一。

位实现加减乘除专题

在计算机中,位运算的效率比单纯加减乘除的效率更高,因此在高性能软件的源码中大量应用。

1. 位运算实现加法

LeetCode 371:给你两个整数 a 和 b ,不使用 运算符 + 和 - ,计算并返回两整数之和。

两个位加的时候,需要考虑两个问题:进位部分是什么?不进位部分是什么?

  • 对于不进位部分(0+0,1+0,0+1)的情况是:相同为0,不同为1(其实是a⊕b)
  • 对于进位部分(1+1),a和b的这一位都是1的时候才会进位,而且进位只能是1(其实是a&b=1),然后位数由1位变成两位,需要手动移位(a & b) << 1

所以:

  • 不进位部分:用a⊕b计算就可以
  • 是否进位,以及进位值使用(a & b) << 1计算即可
int getSum(int a, int b) {while (b != 0) {int sign = (a & b) << 1;//计算出哪些位同时为1(这些需要进位)a = a ^ b; //无进位和b = sign;}return a;}

从低位开始,处理每一位,考虑进位,并逐步向高位移动。

2. 递归乘法

LeetCode 08.05:递归乘法。 写一个递归函数,不使用 * 运算符, 实现两个正整数的相乘。可以使用加号、减号、位移,但要吝啬一些。

示例:

  • 输入: a=1,b=10
  • 输出:10

不用*计算,一种方法是将一个作为循环的参数,对另一个进行累加,但是这样效率太低,所以还要考虑位运算。

首先,需要求得a和b的最小值和最大值,把其中的最小值当做乘数(选最小值当乘数,后续计算算的少),将其拆分成2的幂的和(方便左移),
即min = a0 * 2^0 + a12^1 + a2 2^2 + … + ai2i+…,其中ai取0或者1,相当于用二进制的视角去看待min,比如12用二进制来表示就是1100,即1000+0100
13 * 12 = 13 * (8+4)= 13
8 + 13*4 = (13<<3)+(13<<2);

上面仍然需要左移5次,存在重复计算,可以进一步简化:
假设我们需要的结果是ans
定义临时变量 :tmp = 13<<2 = 52计算后,可以先让ans = 52
然后tmp继续左移一次tmp = 52<<1 = 104,此时再让ans = ans + tmp
此时只要执行三次移位和一次加法

 int multiply(int a, int b) {int min = a < b ? a : b;int max = a > b ? a : b;int ans = 0;for (int i = 0; min != 0; i++) {if ((min & 1) == 1) {ans += max;}min >>= 1;max += max;}return ans;}

END

本文的主要内容来自算法通关村。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot集成RESTful API

在Spring Boot中集成一个RESTful API是我们在实际开发中较为常见的一种开发任务&#xff0c;以下通过一个小的案例来展示在Spring Boot中创建RESTful API来编写一个单元测试。 本节使用到的注解&#xff1a; Controller&#xff1a;修饰class&#xff0c;用来创建处理http请求的…

互联网Java工程师面试题·Spring篇·第四弹

目录 6、AOP 6.1、什么是 AOP&#xff1f; 6.2、什么是 Aspect&#xff1f; 6.3、什么是切点&#xff08;JoinPoint&#xff09; 6.4、什么是通知&#xff08;Advice&#xff09;&#xff1f; 6.5、有哪些类型的通知&#xff08;Advice&#xff09;&#xff1f; 6.6、指出…

Fedora系统的部署与MobaXterm的使用

Fedora Fedora简介 Fedora&#xff0c;Fedora Linux&#xff08;第七版以前为Fedora Core&#xff09;是由Fedora项目社区开发、红帽公司赞助&#xff0c;目标是创建一套新颖、多功能并且自由&#xff08;开放源代码&#xff09;的操作系统。Fedora是商业化的Red Hat Enterpr…

正点原子嵌入式linux驱动开发——Linux INPUT子系统

按键、鼠标、键盘、触摸屏等都属于输入(input)设备&#xff0c;Linux内核为此专门做了一个叫做input子系统的框架来处理输入事件。输入设备本质上还是字符设备&#xff0c;只是在此基础上套上了input框架&#xff0c;用户只需要负责上报输入事件&#xff0c;比如按键值、坐标等…

如何在Android Termux上安装MySQL并实现公网远程访问?

文章目录 前言1.安装MariaDB2.安装cpolar内网穿透工具3. 创建安全隧道映射mysql4. 公网远程连接5. 固定远程连接地址 前言 Android作为移动设备&#xff0c;尽管最初并非设计为服务器&#xff0c;但是随着技术的进步我们可以将Android配置为生产力工具&#xff0c;变成一个随身…

使用Vscode创建一个C_Hello程序

Vscode用来学习C语言语法确实很方便。问题是安装好了&#xff0c;不会用&#xff0c;或编译失败&#xff0c;也是常有的事情&#xff0c;其中一个原因就是不会创建工作区。下面介绍使用Vscode创建一个C语言工作区。有时候看着很简单&#xff0c;时间久了&#xff0c;我竟然忘记…

Centos8: 安装python2, 并设置默认版本

文章目录 原本centos上已经有python3.6了&#xff0c;因为要运行旧代码&#xff0c;需要安装python2版本。 #在CentOS 8上安装Python 2 sudo dnf install python2#设置默认Python版本 python2 sudo alternatives --set python /usr/bin/python2#设置默认Python版本 python3 sud…

机器学习-模型评估与选择

文章目录 评估方法留出法交叉验证自助法 性能的衡量回归问题分类问题查准率、查全率与F1ROC与AUC 在机器学习中&#xff0c;我们通常面临两个主要问题&#xff1a;欠拟合和过拟合。欠拟合指模型无法在训练数据上获得足够低的误差&#xff0c;通常是因为模型太简单&#xff0c;无…

SMART PLC飞剪控制算法

如何通过编码器计算材料输送长度和速度,这里其实是属于计米和测速应用,在专栏里有详细介绍大家可以自行搜索,常用链接如下: 【精选】如何通过编码器信号计算输送线/输送带线速度(飞剪、追剪算法基础)_追剪控制算法-CSDN博客文章浏览阅读2.3k次。不同品牌PLC如何采集编码…

Node编写获取用户信息接口

目录 前言 初始化路由模块 使用postman发送get获取用户信息请求 初始化路由处理函数模块 获取用户基本信息 前言 在前两篇文章中已经介绍了如何编写用户注册接口以及用户登录接口&#xff0c;这篇文章介绍如何获取用户信息&#xff0c;本篇文章建立在Node编写用户登录接口…

依靠继承与聚合,实现maven搭建分布式项目

简介聚合 对于复杂的Maven项目&#xff0c;一般建议采用多模块的方式来设计开发&#xff0c;便于后期维护管理。但是构建项目时&#xff0c;如果每次都需要按模块一个一个进行构建会十分麻烦&#xff0c;而Maven的聚合功能就可以很好的解决这个问题&#xff0c;当用户对聚合模…

OpenCV官方教程中文版 —— 直方图的计算,绘制与分析

OpenCV官方教程中文版 —— 直方图的计算&#xff0c;绘制与分析 前言一、原理1.统计直方图2. 绘制直方图3. 使用掩模 前言 • 使用 OpenCV 或 Numpy 函数计算直方图 • 使用 Opencv 或者 Matplotlib 函数绘制直方图 • 将要学习的函数有&#xff1a;cv2.calcHist()&#xf…

重装win11,个人记录详细步骤-干货

重装win11&#xff0c;个人记录详细步骤-干货 下载镜像-windows官网 https://www.microsoft.com/zh-cn/software-download/windows11%20 安装的选这个就行 虽然他这里写的是家庭版&#xff0c;进去里面就可以选择其他版本 重装win11有个前提 系统最低要求 本文列出了 Windo…

13.4web自动化测试(Selenium3+Java)

一.定义 用来做web自动化测试的框架. 二.特点 1.支持各种浏览器. 2.支持各种平台(操作系统). 3.支持各种编程语言. 4.有丰富的api. 三.工作原理 四.搭环境 1.对照Chrome浏览器版本号,下载ChromeDriver,配置环境变量,我直接把.exe文件放在了jdk安装路径的bin文件夹下了(j…

FFmpeg编译安装(windows环境)以及在vs2022中调用

文章目录 下载源码环境准备下载msys换源下载依赖源码位置 开始编译编译x264编译ffmpeg 在VS2022写cpp调用ffmpeg 下载源码 直接在官网下载压缩包 这个应该是目前&#xff08;2023/10/24&#xff09;最新的一个版本。下载之后是这个样子&#xff1a; 我打算添加外部依赖x264&a…

12、Python -- if 分支 的讲解和使用

目录 程序结构顺序结构分支结构分支结构注意点不要忘记冒号 if条件的类型if条件的逻辑错误if表达式pass语句 程序流程 分支结构 分支结构的注意点 if条件的类型 if语句的逻辑错误 if表达式 程序结构 Python同样提供了现代编程语言都支持的三种流程 顺序结构 分支结构 循环结构…

Unity DOTS系列之Filter Baking Output与Prefab In Baking核心分析

最近DOTS发布了正式的版本, 我们来分享一下DOTS里面Baking核心机制&#xff0c;方便大家上手学习掌握Unity DOTS开发。今天给大家分享的Baking机制中的Filter Baking Output与Prefab In Baking。 对啦&#xff01;这里有个游戏开发交流小组里面聚集了一帮热爱学习游戏的零基础…

SQL Delete 语句(删除表中的记录)

SQL DELETE 语句 DELETE语句用于删除表中现有记录。 SQL DELETE 语法 DELETE FROM table_name WHERE condition; 请注意删除表格中的记录时要小心&#xff01;注意SQL DELETE 语句中的 WHERE 子句&#xff01; WHERE子句指定需要删除哪些记录。如果省略了WHERE子句&#xff…

【数据结构】数组和字符串(二):特殊矩阵的压缩存储:对角矩阵——一维数组

文章目录 4.2.1 矩阵的数组表示4.2.2 特殊矩阵的压缩存储a. 对角矩阵的压缩存储结构体初始化元素设置元素获取打印矩阵主函数输出结果代码整合 4.2.1 矩阵的数组表示 【数据结构】数组和字符串&#xff08;一&#xff09;&#xff1a;矩阵的数组表示 4.2.2 特殊矩阵的压缩存储…

UG\NX二次开发 实现“适合窗口”的功能

文章作者:里海 来源网站:王牌飞行员_里海_里海NX二次开发3000例,里海BlockUI专栏,C\C++-CSDN博客 感谢粉丝订阅 感谢 shsjdj 订阅本专栏,非常感谢。 简介 实现“适合窗口”的功能 效果 代码1 #include "me.hpp"extern DllExport void ufusr(char* param, int* re…