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

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

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

位移的妙用

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请求的…

深入理解NLP

引子 自然语言处理&#xff08;Natural Language Processing, NLP&#xff09;是人工智能领域中的一个重要研究方向&#xff0c;它涉及了计算机与人类自然语言之间的交互和理解。 1. NLP的起源与发展 NLP的起源可以追溯到早期的机器翻译项目&#xff0c;随着科技的进步&…

nfsiostat 命令

nfsiostat 命令 nfsiostat 命令用作服务器上 NFS 挂载点的 iostat 命令。 它使用文件 /proc/self/mountstats 作为输入&#xff0c;并提供有关系统中挂载的 NFS 共享的输入/输出性能的信息。 下面是 nfsiostat 命令的示例输出。 下表显示了关于输出中每一列的简短描述。 字段…

互联网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…

oracle统计信息

1. 查看表的统计信息 1.建表 SQL> create table test as select * from dba_objects;2.查看表的统计信息 select owner, table_name, num_rows, blocks, avg_row_lenfrom dba_tableswhere owner SCOTTand table_name TEST; OWNER TABLE_NAME NUM_ROWS BLO…

说说对ajax、axios、jsonp的理解

下面是对 AJAX、Axios 和 JSONP 的简要说明&#xff1a; 1&#xff1a;AJAX&#xff08;Asynchronous JavaScript and XML&#xff09;&#xff1a; AJAX 是一种用于创建异步通信的技术&#xff0c;通过在后台与服务器进行数据交换&#xff0c;实现页面的局部更新&#xff0c…

正点原子嵌入式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编写用户登录接口…

python 虚拟环境搭建、打包成exe发布和所遇到的问题汇总

python 虚拟环境搭建、打包成exe发布和所遇到的问题汇总 文章目录 python 虚拟环境搭建、打包成exe发布和所遇到的问题汇总1.项目用到的软件2.python虚拟环境安装3.问题和解决&#xff1a;3.1使用pyinstaller编译文件为exe产生1.WARNING: file already exists but should not: …

XTU-OJ 1150-n!进制

题目描述 n!进制是指每i位的权值是(i1)!,每一位的系数为0~i1。 比如n!进制的21 2*2! 1*1! 5。给你一个10进制数&#xff0c;求其n&#xff01;进制的值。 输入 每行一个10进制的整数n,0≤n≤3,628,799。 输出 每行输出一个样例的结果。 样例输入 0 1 10 100 3628799样例输出…

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

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

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

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

导入自己的jacoco exec文件到IDEA并进行展示

哈喽各位&#xff0c;许久没写过文章了&#xff0c;今天更新一篇将自己本地的jacoco exec文件导入到IDEA中并展示 jacoco是一个用来分析代码覆盖率的三方工具&#xff0c;并且IDEA中也集成了该功能&#xff0c;可以在IDEA中直接生成jacoco覆盖率&#xff0c;但如果我们有一个现…

Java线程中sleep()、wait()、yield()、join()方法的使用

1.sleep() sleep(): sleep 方法属于 Thread 类&#xff0c;该行为中线程不会释放锁&#xff0c;只阻塞线程&#xff0c;让出cpu给其他线程&#xff0c;当达到指定的时间后会自动恢复运行状态继续运行。 2.wait() wait(): 该方法属于 Object 类&#xff0c;在这个过程里线程会…