【算法】位运算

目录

01. 整数在内存中的存储

01.1 无符号整数的表示方法

01.2 有符号整数的表示方法

02. 移位操作符

02.1 左移操作符

1 << n = 2的n次幂

02.2 右移操作符

n >> 1 和 n / 2

03. 位操作符

03.1 按位与

n & 1 和 n % 2

n >> i & 1

n & (n - 1)

03.2 按位或

03.3 按位异或

a ^ a = 0    0 ^ a = a

1. 比特位计数(简单)

2. 只出现一次的数字(简单)

3. 只出现一次的数字 II(中等)

4. 最大单词长度乘积(中等)


01. 整数在内存中的存储

整数在计算机中以二进制数表示。

整数表示的范围在头文件limits.h中定义。

01.1 无符号整数的表示方法

unsigned int a = 25;

00000000000000000000000000011001       1×2^4+1×2^3+0×2^2+0×2^1+1×2^0=25

高位<------------------------------------->低位

n位可以表示的无符号整数的范围是0~2^{n}-1

无符号整数类型最小值最大值
unsigned char0255
unsigned short065535
unsigned int04294967295

01.2 有符号整数的表示方法

有符号整数有3种二进制表示方法,即原码、反码和补码。最高位为符号位,0表示正数,1表示负数,其余为数值位。在计算机中整数以补码的形式存储。

原码:直接将数值按照正负数的形式翻译成二进制。

正数的反码、补码与原码相同。负数的反码、补码要经过如下计算。

反码:将原码的符号位不变,其他位依次按位取反。补码:反码+1就得到补码。

int a = -25;
// 原码:10000000000000000000000000011001
// 反码:11111111111111111111111111100110
// 补码:11111111111111111111111111100111

8位有符号整数的取值范围如下图所示:(补码10000000不表示-0,表示-128)

 n位可以表示的无符号整数的范围是-2^{n-1}~2^{n-1}-1

有符号整数类型最小值最大值
signed char-128127
signed short-3276832767
signed int-21474836482147483647

02. 移位操作符

02.1 左移操作符

整数的二进制表示有3种:原码、反码、补码。正整数的原码、反码、补码相同。负整数的反码是原码符号位不变,其他位按位取反,补码是反码+1。整数在内存中存储的是补码。

+7:
原码:00000000000000000000000000000111
反码:00000000000000000000000000000111
补码:00000000000000000000000000000111
-7:
原码:10000000000000000000000000000111
反码:11111111111111111111111111111000
补码:11111111111111111111111111111001

移位规则:左边抛弃,右边补0

int a = 7;
int b = a << 1;

0[00000000000000000000000000001110]

int a = -7;
int b = a << 1;

1[11111111111111111111111111110010]

1 << n = 2的n次幂

int a = 1;
int b = a << 1;

0[00000000000000000000000000000010]=2的1次幂

int b = a << 2;

00[00000000000000000000000000000100]=2的2次幂

int b = a << 3;

000[00000000000000000000000000001000]=2的3次幂

所以,1<<n=2的n次幂

02.2 右移操作符

移位规则:

  • 逻辑移位:左边补0,右边抛弃
  • 算术移位:左边补原符号位,右边抛弃(常见编译器都是算术移位)

算术移位:

int a = 7;
int b = a >> 1;

[00000000000000000000000000000011]1

int a = -7;
int b = a >> 1;

[11111111111111111111111111111100]1

n >> 1 和 n / 2

n为非负数时,n>>1=n/2          10>>1=5      10/2=5,0>>1=0      0/2=0

n为负偶数时,n>>1=n/2          -10>>1=-5  -10/2=-5

n为负奇数时,n>>1=n/2-1       -5>>1=-3      -5/2=-2(n>>1是n除以2向下取整,n/2是n除以2向上取整)

03. 位操作符

&按位与,|按位或,^按位异或

位操作符通过逐位比较两个运算对象,生成一个新值。对于每个位:

  • &:两个操作数相应的位都为1,结果为1
  • | :两个操作数相应的位至少有一个为1,结果为1
  • ^:两个操作数相应的位相同为0,相异为1

03.1 按位与

int a = 3;
int b = -5;
int c = a & b;
 3的补码:00000000000000000000000000000011
-5的补码:11111111111111111111111111111011c的补码:00000000000000000000000000000011

n & 1 和 n % 2

n为非负数时,n&1=n%2

  • n为奇数:n&1=1  n%2=1
  • n为偶数:n&1=0  n%2=0

n为负数时,

  • n为奇数:n&1=1  n%2=-1
  • n为偶数:n&1=0  n%2=0

n >> i & 1

n>>i&1用来获取二进制的每一位。

以75(000000000000000000000001001011)为例:

要想获取最后一位,就要&1,即

 000000000000000000000001001011
&000000000000000000000000000001
=000000000000000000000000000001
=1

要想获取倒数第二位,就要>>1,再&1,即

75>>1=[000000000000000000000000100101]1

 000000000000000000000000100101
&000000000000000000000000000001
=000000000000000000000000000001
=1

要想获取倒数第三位,就要>>2,再&1,即

75>>2=[000000000000000000000000010010]11

 000000000000000000000000010010
&000000000000000000000000000001
=000000000000000000000000000000
=0

n & (n - 1)

n-1表示将n的二进制位最右边的1变为0,该1右边的所有0都变为1。

n&(n-1)表示将n的二进制位最右边的1变为0,其余位不变。

24:       00000000000000000000000000011000

23:       00000000000000000000000000010111

24&23:00000000000000000000000000010000

如果n&(n-1)为0,则n是2的幂。

+2:  00000000000000000000000000000010

+1:  00000000000000000000000000000001

+4:  00000000000000000000000000000100

+3:  00000000000000000000000000000011

2&1:00000000000000000000000000000000

4&3:00000000000000000000000000000000

03.2 按位或

int a = 3;
int b = -5;
int c = a | b;
 3的补码:00000000000000000000000000000011
-5的补码:11111111111111111111111111111011c的补码:11111111111111111111111111111011

03.3 按位异或

int a = 3;
int b = -5;
int c = a ^ b;
 3的补码:00000000000000000000000000000011
-5的补码:11111111111111111111111111111011c的补码:11111111111111111111111111111000

a ^ a = 0    0 ^ a = a

a^a=0:

如,3^3=00000011^00000011=00000000

0^a=a:

如,0^3=00000000^00000011=00000011

不创建临时变量实现两个数的交换:

#include <stdio.h>int main()
{int a = 10;int b = 20;a = a ^ b; // 10^20b = a ^ b; // 10^20^20=10^0=10(^操作符支持交换律)a = a ^ b; // 10^20^10=0^20=20printf("a = %d b = %d\n", a, b);return 0;
}

1. 比特位计数(简单)

方法一:

vector<int> countBits(int n)
{vector<int> ret(n + 1, 0); // 创建n+1个元素的数组,将所有元素初始化为0// 0的二进制形式中没有1,现在ret[0]的值已经为0,所以可以从1开始计算for (int i = 1; i <= n; i++){int n = i;while (n){ret[i]++;// 每进行一次n&(n-1)的操作,就能去掉最后一个1,去掉所有的1时(n为0时)结束循环// 二进制位1的个数=循环的次数n = n & (n - 1);}}return ret;
}

如果一个整数共有k位,对于每个整数,while循环最多循环k次,每次循环的时间复杂度为O(1),因此上述代码的时间复杂度为O(kn)。

方法二:

vector<int> countBits(int n)
{vector<int> ret(n + 1, 0); // 创建n+1个元素的数组,将所有元素初始化为0// 0的二进制形式中没有1,现在ret[0]的值已经为0,所以可以从1开始计算for (int i = 1; i <= n; i++){// i的二进制形式中1的个数比i&(i-1)的二进制形式中1的个数多1个ret[i] = ret[i & (i - 1)] + 1;}return ret;
}

上述代码的时间复杂度为O(n)。

方法三:

如果正整数i是偶数,那么i相当于将i/2左移一位的结果,因此偶数i和i/2的二进制形式中1的个数是相同的。

如果正整数i是奇数,那么i相当于将i/2左移一位后,再将最右边一位设为1的结果,因此奇数i的二进制形式中1的个数比i/2的二进制形式中1的个数多1个。

例如,

3:00000000000000000000000000000011

6:00000000000000000000000000000110

7:00000000000000000000000000000111

vector<int> countBits(int n)
{vector<int> ret(n + 1, 0); // 创建n+1个元素的数组,将所有元素初始化为0// 0的二进制形式中没有1,现在ret[0]的值已经为0,所以可以从1开始计算for (int i = 1; i <= n; i++){// ret[i] = ret[i / 2] + (i % 2);// 当i为非负数时,i/2=i>>1,i%2=i&1,且位运算比除法运算和取余运算效率高// 代码优化如下:ret[i] = ret[i >> 1] + (i & 1);}return ret;
}

上述代码的时间复杂度为O(n)。

2. 只出现一次的数字(简单)

a ^ a = 0    0 ^ a = a

class Solution {
public:int singleNumber(vector<int>& nums) {// 4^1^2^1^2=4^0=4int n = nums.size();int ans = 0;for (int i = 0; i < n; i++){ans ^= nums[i];}return ans;}
};

3. 只出现一次的数字 II(中等)

将数组中只出现一次的元素剔除,剩下的元素都出现了三次,将这些元素的各个数位的值相加,各个数位的和一定是3的倍数。

将数组中所有元素的各个数位的值相加:

  • 如果某位的和能被3整除,说明只出现1次的元素该位是0
  • 如果某位的和被3除余1,说明只出现1次的元素该位是1
class Solution {
public:int singleNumber(vector<int>& nums) {int n = nums.size();vector<int> bitSums(32, 0); // int型有32位for (int i = 0; i < n; i++){for (int j = 0; j < 32; j++){bitSums[j] += nums[i] >> (31 - j) & 1;}}int ret = 0;for (int i = 0; i < 32; i++){ret = (ret << 1) + bitSums[i] % 3;}return ret;}
};

4. 最大单词长度乘积(中等)

用int型整数记录某个字符串中出现的字符。

如果字符串中包含'a',那么整数最右边的数位为1,

如果字符串中包含'b',那么整数倒数第2的数位为1 ……

用flags[i]记录words[i]出现的字符,如果flags[i] & flags[j] == 0,那么words[i]和words[j]没有相同字符,此时可以计算它们长度的乘积,然后和之前计算过的最大值比较。

class Solution {
public:int maxProduct(vector<string>& words) {int n = words.size();vector<int> flags(n, 0);// 设置flags[i]for (int i = 0; i < n; i++){for (int j = 0; j < words[i].size(); j++){flags[i] |= 1 << (words[i][j] - 'a');}}// 找没有相同字符的words[i]和words[j]int ans = 0;for (int i = 0; i < n; i++){for (int j = i + 1; j < n; j++){if ((flags[i] & flags[j]) == 0){int prod = words[i].size() * words[j].size();ans = max(ans, prod);}}}return ans;}
};

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

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

相关文章

springboot3.0更新后,idea创建springboot2.x项目

springboot3.0更新后&#xff0c;idea创建springboot2.x项目 点击以下红色框中的按钮 出现了如下图所示&#xff1a; 到这里我们发现没有jdk8的版本&#xff0c;不要慌&#xff0c;我们可以先在这里选择21&#xff0c;然后进入到真正的项目中手动去修改这个jdk的版本&#xff0…

几分钟在Ubuntu搭建本地Emlog博客网站并发布至公网无需购买域名服务器

文章目录 前言1. 网站搭建1.1 Emolog网页下载和安装1.2 网页测试1.3 cpolar的安装和注册 2. 本地网页发布2.1 Cpolar临时数据隧道2.2.Cpolar稳定隧道&#xff08;云端设置&#xff09;2.3.Cpolar稳定隧道&#xff08;本地设置&#xff09; 3. 公网访问测试总结 前言 博客作为使…

基于JavaSE+JDBC使用控制台操作的简易购物系统【源码+数据库】

1、项目简介 本项目是一套基于JavaSEJDBC使用控制台操作的简易购物系统&#xff0c;主要针对计算机相关专业的正在做bishe的学生和需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目可以直接作为bishe使用。 项目都经过严格调试&…

应用程序中实现用户隐私合规和数据保护合规的处理方案及建议

随着移动互联网的发展&#xff0c;用户隐私合规和数据保护合规已经成为应用开发过程中不可忽视的重要环节。为了帮助开发者实现隐私和数据保护合规&#xff0c;本文将介绍一些处理方案和建议。 图片来源&#xff1a;应用程序中实现用户隐私合规和数据保护合规的处理方案及建议 …

SQL Server数据库的备份和还原

6.2 SQL Server备份和还原 数据库管理员最担心的情况就是数据库瘫痪&#xff0c;造成数据丢失&#xff0c;而备份作为数据的副本&#xff0c;可以有 效地保护和恢复数据。本节将介绍数据备份的原因&#xff0c;备份的方式.SOL Server的恢复模式.以及备 份策略和备份设备。 6.2…

每日汇评:在周五美国非农数据公布前,黄金上行空间有限

金价周四早间在2020美元上方巩固了此前的反弹&#xff1b; 随着美债收益率趋于稳定&#xff0c;美元处于三周高点&#xff1b; 黄金价格在第四季度图表上看起来很脆弱&#xff0c;焦点转向美国非农就业数据&#xff1b; 昨日早些时候&#xff0c;由于市场情绪依然疲软&#xff…

docker安装Postgres-XL集群及踩过的N个坑

说明&#xff1a;本文是在一个机器内部用docker创建了三台centos&#xff0c;然后构建的pgxl集群 文章目录 1. 学习docker2. 创建三台centos3. 安装SSH4. 创建新用户postgres5. 关闭防火墙 关闭selinux6. 配置免密登录7. 下载并传输Postgres-XL的源码8. 配置环境变量10. 安装11…

[TKDE2020]@Multi-Source_Spatial_Entity_Linkage

论文地址&#xff1a;https://arxiv.org/pdf/1911.09016v1.pdf&#xff08;下文中提及的引用信息如未解释&#xff0c;请索引原论文末的参考文献&#xff09; 论文中提到的SSTD2019Multi-Source Spatial Entity Linkage (提取码&#xff1a;i3xt) 论文重要部分翻译 Abstract …

【Java系列】函数式接口编程

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

视界臻色彩 轻巧薄未来 《2023年中国OLED电视发展白皮书》发布

随着中国经济迈入新周期&#xff0c;彩电行业也进入存量竞争阶段。在此背景下&#xff0c;主流品牌围绕新产品、新技术、新应用等方面积极发力&#xff0c;特别是在高端彩电市场的争夺中&#xff0c;伴随着三星OLED的入局开始变得愈发激烈。我国“十三五”规划中明确指出&#…

MySQL高级--01_1--数据库缓冲池(buffer pool)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 数据库缓冲池(buffer pool)DBMS 会申请占用内存来作为数据缓冲池&#xff0c;在真正访问页面之前&#xff0c;需要把在磁盘上的页缓存到内存中的Buffer Pool 之后才…

2024年网络安全比赛--系统渗透测试(超详细)

一、竞赛时间 180分钟 共计3小时 二、竞赛阶段 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 1.在渗透机中对服务器主机进行信息收集&#xff0c;将服务器开启的端口号作为 Flag 值提交; 2.在渗透机中对服务器主机进行渗透&#xff0c;在服务器主机中获取服务器主机名称&#xff…

MX6ULL学习笔记 (八) platform 设备驱动实验

前言&#xff1a; 什么是 Linux 下的 platform 设备驱动 Linux下的字符设备驱动一般都比较简单&#xff0c;只是对IO进行简单的读写操作。但是I2C、SPI、LCD、USB等外设的驱动就比较复杂了&#xff0c;需要考虑到驱动的可重用性&#xff0c;以避免内核中存在大量重复代码&…

全志XR806蓝牙透传(单向)测试

评测三 蓝牙透传(单向) 有时无线透传在无法布线时有很方便的效用&#xff0c;不妨试试蓝牙透传&#xff0c;效果如下&#xff1a; 具体是无线数据->串口数据&#xff0c;串口数据->无线数据&#xff0c;目前前者实现了&#xff0c;后者还有些问题未解决&#xff0c; 实现…

支持生成接口文档!Apipost IDEA插件使用体验

前言 Idea 是一款功能强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;它可以帮助开发人员更加高效地编写、调试和部署软件应用程序,Idea 还具有许多插件和扩展&#xff0c;可以根据开发人员的需要进行定制和扩展&#xff0c;从而提高开发效率,今天我们就来介绍一款…

持续集成交付CICD:Sonarqube多分支代码扫描

目录 一、实验 1.Sonarqube安装插件 2.Sonarqube多分支代码扫描 一、实验 1.Sonarqube安装插件 &#xff08;1&#xff09;不同软件版本对应不同插件版本 &#xff08;2&#xff09;插件对应版本下载安装 将下载好的插件包&#xff08;sonarqube-community-branch-plugin…

三层交换机配置DHCP服务

第一步&#xff1a;进入二层交换机Switch 1&#xff09;输入命令&#xff1a; Switch(config)#vlan 10 Switch(config)#vlan 20 2&#xff09;修改F0/1 和F0/2为access口&#xff0c;F0/24为trunk口 第二步&#xff1a;进入三层交换机 1&#xff09;输入命令 Switch(config)#…

每日一练2023.12.7—— 情人节【PTA】

题目链接&#xff1a;L1-035 情人节 题目要求&#xff1a; 以上是朋友圈中一奇葩贴&#xff1a;“2月14情人节了&#xff0c;我决定造福大家。第2个赞和第14个赞的&#xff0c;我介绍你俩认识…………咱三吃饭…你俩请…”。现给出此贴下点赞的朋友名单&#xff0c;请你找出…

PPT设置章节

0 Preface/Foreward 1 添加章节方法 选择 > 开始 > 节 可以进行&#xff1a; 新增节重命名节删除所有节 相关节的内容如下&#xff1a;

超大规模集成电路设计----FPGA时序模型及FSM的设计(八)

本文仅供学习&#xff0c;不作任何商业用途&#xff0c;严禁转载。绝大部分资料来自----数字集成电路——电路、系统与设计(第二版)及中国科学院段成华教授PPT 超大规模集成电路设计----RTL级设计之FSM&#xff08;八&#xff09; 7.1 CPLD的时序模型7.1.1 XPLA3 时序模型7.1.…