算法 —— 位运算

news2024/9/28 23:29:27

目录

位运算常用结论

位运算例题

位1的个数

比特位计算

 汉明距离

只出现一次的数字

判定字符是否唯一

丢失的数字

两整数之和

 消失的两个数字

进制转换


位运算常用结论

想详细了解位运算的内容可以阅读我的这篇博客:应该背下的位运算

以下我只介绍一些位运算的常用结论:

1、基础位运算:我们只需要记住以下口诀:

  1. &按位与:有0就是0
  2. | 按位或:有1就是1
  3. ^ 按位异或:相同为0,相异为1 / 无进制相加(两个1相加不向高处进位)

2、给一个数n,确定它的二进制表示中的第 x 位是0还是1

        ( n >> x ) & 1

3、将一个数n的二进制表示的第 x 位修改成1

        n | = ( 1 << x ) 

4、将一个数n的二进制表示的第 x 位修改成0

        n & = ( ~ ( 1 << x ) )

5、提取一个数n的二进制表示中最右侧的1

        n & -n

6、干掉一个数n的二进制表示中最右侧的1

        n & ( n - 1 )

7、异或运算律

  1. a ^ 0 = a
  2. a ^ a = 0
  3. a ^ b ^ c  = a ^ ( b ^ c )

位运算例题

位1的个数

利用上述第二个结论即可AC,代码如下:

class Solution {
public:
    int hammingWeight(int n) {
        int count = 0;
        while (n)
        {
            if (n & 1)
                count++;
            n >>= 1;
        }
        return count;
    }
};

比特位计算

 这里为了减小时间复杂度,我们利用动态规划进行完善,代码如下:

class Solution {
public:
    vector<int> countBits(int n) {
        vector<int> ret(n + 1, 0);
        for (int i = 1; i <= n; i++)
        {
            if (i % 2) // 如果是奇数,那么就是前一个偶数的所有的1加1
                ret[i] = ret[i - 1] + 1;
            else // 如果是偶数,那么则等于它除二后的个数
                ret[i] = ret[i / 2];
        }
        return ret;
    }
};

为什么这里能用动态规划解决呢?好好思考一下,一个偶数变成一个奇数需要加一或者减一,在二进制上最直观的表现是最低位是否为1,如果为1那么就是奇数,如果为0那么就是偶数,这样就能够解释if语句里的内容了。

那么else语句中是什么意思呢?以6,3为例,6的二进制为110,3的二进制为11,二进制里的计算方式是一个二项式定理,这里不难发现,6是从3这样变化而来的:
2^{2}+2^{1} = \left ( 2^{1} + 2^{0} \right )*2


 汉明距离

两个数异或一下就能判别出所有1的二进制位,代码如下:

class Solution {
public:
    int hammingDistance(int x, int y) {
        int tmp = x ^ y, count = 0;
        while (tmp)
        {
            if (tmp & 1)
                count++;
            tmp >>= 1;
        }
        return count;
    }
};

只出现一次的数字

LeetCode —— 只出现一次的数字


判定字符是否唯一

大家先看一下我之前写的代码:

class Solution {
public:
    bool isUnique(string astr) {
        sort(astr.begin(), astr.end());
        for (int i = 1; i < astr.size(); i++)
            if (astr[i] == astr[i - 1])
                return false;
        return true;
    }
};

 直接排序加比较,时间复杂度稍微有些高,我们用位运算看能不能一次遍历就能找到正确答案:

class Solution {
public:
    bool isUnique(string astr) {
        // 比26字母表还大说明必定有重复
        if (astr.size() > 26)
            return false;
        int bitMap = 0;
        for (auto& ch : astr)
        {
            int tmp = ch - 'a';
            // 如果位图中的这一位存在了就说明已出现过
            if ((bitMap >> tmp) & 1)
                return false;
            // 第一次出现的加入到位图中
            bitMap |= (1 << tmp);
        }
        return true;
    }
};

这里我们使用一个int类型的变量来存值,可以存32个比特位,二进制位为0表示没出现,1为出现


丢失的数字

由于本题元素是一个等差数列,可以用求和公式直接计算出正常序列的和, 我们也可以用位运算解决这个问题,利用相同数字异或为0的结论即可AC,代码如下:

class Solution {
public:
    int missingNumber(vector<int>& nums) {
        int ret = 0;
        for (int i = 1; i <= nums.size(); i++)
            ret ^= (i ^ nums[i - 1]);
        return ret;
    }
};

两整数之和

这里又需要一个新的结论:进位,两个数进行按位与运算,如果有进位就左移一位

比如101和110相加,得到1011。最低位和第一位按位与之后变成0,第二位按位与后变成1,说明他是两个1相加的,意味着要进位,所以向左移动一位。

在文章最开始提到,异或运算是无进制相加,意味着它只能识别不要进位的那些二进制位,这时候我们把进位和异或运算结合在一起就可以实现不用加减运算符达到两整数之和的目的。

 以13+28为例,我们可以看到此方法可行,具体代码如下:

class Solution {
public:
    int getSum(int a, int b) {
        while (b)
        {
            int tmpa = a, tmpb = b;
            a = tmpa ^ tmpb; b = (tmpa & tmpb) << 1;
        }
        return a;
    }
};

 消失的两个数字

 本题用到了丢失的数字和只出现一次的数字里的知识,内容可看链接。

这里我们可以想象为正常序列和缺少的两个数字的缺失序列并在一起的大序列,其中有两个数字出现了一次,另外数字出现了两次,那么就可以进行分组。

我们把所有数字异或在一起,得到缺失两个数字异或的值,由于两个数字异或不可能等于0,所以他们最少有一个位不同,异或后的那个值1的最低位就是不同位,以这个为判定标准进行分组,代码如下:

class Solution {
public:
    vector<int> missingTwo(vector<int>& nums) {
        int tmp = 0; // tmp是缺失两个数异或得到的结果
        for (int i = 1; i <= nums.size() + 2; i++)
            tmp ^= i;
        for (auto& n : nums)
            tmp ^= n;
        vector<int>ret(2, 0); // 存放缺失的两个数
        int lowbit = tmp & -tmp; // 找到比特位为1的最低位
        for (auto& e : nums)// 分两组  
            ret[(e & lowbit) != 0] ^= e; // 注意加括号
        for (int i = 1; i <= nums.size() + 2; i++)
            ret[(i & lowbit) != 0] ^= i;
        return ret;
    }
};

进制转换

本题就不再是二进制位运算的解决方法了,很显然要解决这种题型首先要了解进制转换的规则:

n进制位转换成十进制位不用多说,一个求和累加公式即可,那么10进制转换为2进制怎么做呢?

我们利用不断除n得到余数,最后余数逆置就是转换后的结果,如图23从十进制转换为二进制,通过这个特性可以用代码来进行实现。

#include<bits/stdc++.h>
using namespace std;

int fn, ln; string num, ret;
long long tn, d = 1;

int main()
{
	cin >> fn >> num >> ln;
	for (int i = num.size() - 1; i >= 0; i--)
	{
		if (num[i] >= 'A' && num[i] <= 'F')
			tn += (num[i] - 'A' + 10) * d;
		else
			tn += (num[i] - '0') * d;
		d *= fn;
	}
	while (tn)
	{
		int tmp = tn % ln; tn /= ln;
		if (tmp >= 10)
			ret += (tmp - 10 + 'A');
		else
			ret += to_string(tmp);
	}
	reverse(ret.begin(), ret.end());
	cout << ret << endl;
	return 0;
}

如果出现了基数是负数的情况还能不断除法取余吗,答案是可以的,我们要怎么处理余数为负数的情况呢 ?这是除法运算法则:

被除数 = 商 * 除数 + 余数

当被除数或除数有一者为负数时就会出现余数为负数的情况,我们要避免这个情况发生,只需要将商+1,余数-除数即可,因为余数(绝对值)一定小于除数,所以这样就可以将余数转换为正数:

(商+1)* 除数 +(余数 - 除数)= 商 * 除数 + 除数 + 余数 - 除数 = 商 * 除数 + 余数 =被除数

 按照这个式子可以实现负进制的情况,代码实现如下:

#include<bits/stdc++.h>
using namespace std;
int num, r;
string ret;

int main()
{
	cin >> num >> r; int d = num;
	while (num)
	{
		int tmp = num % r;
		if (tmp < 0)
		{
			tmp -= r;
			num += r;
		}
		if (tmp >= 10)
			ret += (tmp - 10 + 'A');
		else
			ret += to_string(tmp);
		num /= r;
	}
	reverse(ret.begin(), ret.end());
	cout << d << '=' << ret << "(base" << r << ')' << endl;
	return 0;
}

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

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

相关文章

61850 MMS源码(二)

上一篇说了怎么下载&#xff0c;编译和运行mms相关的源码&#xff0c;以及如何抓包。这篇尝试对源码做出一些改动&#xff0c;并实际运行一下。 协议内容厚厚一本书&#xff0c;只是大概看了一下&#xff0c;个人比较习惯从代码入手看逻辑处理&#xff0c;从而理解协议。 我发现…

独立摄影师如何找到自己的第一批客户?

声明&#xff1a;此篇为 ai123.cn 原创文章&#xff0c;转载请标明出处链接&#xff1a;独立摄影师如何找到自己的第一批客户&#xff1f; | AI导航 ai123.cn 嘿&#xff0c;摄影师朋友们&#xff01;咱都知道&#xff0c;想增加目标客户可不简单&#xff0c;推广难、竞争大&am…

Jmeter--http信息头管理器的使用(转载)

本文转载自&#xff1a; Jmeter—什么时候需要配置HTTP信息头管理器以及对应的参数如何输入_信息头管理器中的参数怎么调用-CSDN博客 1、抓包查看Request Headers&#xff08;请求头&#xff09;里Content-Type的信息&#xff0c;如下图&#xff1a; Content-Type的格式为&…

ROS2从入门到精通4-6:路径平滑插件开发案例(以B样条曲线平滑为例)

目录 0 专栏介绍1 ROS2路径平滑器介绍2 平滑器插件编写模板2.1 构造平滑器插件类2.2 注册并导出插件2.3 编译与使用插件 3 基于B样条曲线的路径平滑 0 专栏介绍 本专栏旨在通过对ROS2的系统学习&#xff0c;掌握ROS2底层基本分布式原理&#xff0c;并具有机器人建模和应用ROS2…

了解一下这个基质:粘弹性可编码,organoids培养的好帮手

Dynamic matrices with DNA-encoded viscoelasticity for cell and organoid culture是发表于《nature nanotechnology》的一篇文章&#xff0c;介绍了一种基于DNA的动态交联基质DyNAtrix&#xff0c;用于细胞和类器官培养。DyNAtrix由DNA库与超高分子量聚合物自组装形成&#…

联手体系结构专业委员会:“用户态GPU池化技术”术语发布 | CCF术语快线

本期发布术语热词&#xff1a;用户态GPU池化技术&#xff08;User-space GPU Pooling&#xff09;。 用户态GPU池化技术 作者&#xff1a;陈飞&#xff08;趋动科技&#xff09;张伟韬&#xff08;趋动科技&#xff09;李诚&#xff08;中国科学技术大学&#xff09; 开篇导语…

python使用boto3访问S3对象存储并列出百万级文件对象的存储信息

本文提供了在python3环境里使用boto3访问S3对象存储&#xff0c;并列出百万级文件对象的存储信息的示例代码。 一、测试环境 操作系统和python版本如下&#xff1a; [rootlocalhost boto3]# cat /etc/os-release NAME"openEuler" VERSION"22.03 LTS" I…

【实战指南】轻松上手:部署与应用清华智谱GLM大模型

部署一个自己的大模型&#xff0c;没事的时候玩两下&#xff0c;这可能是很多技术同学想做但又迟迟没下手的事情&#xff0c;没下手的原因很可能是成本太高&#xff0c;近万元的RTX3090显卡&#xff0c;想想都肉疼&#xff0c;又或者官方的部署说明过于简单&#xff0c;安装的时…

GreatSQL 8.0.32-26 今日发布

GreatSQL 8.0.32-26 今日发布 版本信息 发布时间&#xff1a;2024年08月05日 版本号&#xff1a;8.0.32-26, Revision a68b3034c3d 下载链接&#xff1a;https://gitee.com/GreatSQL/GreatSQL/releases/tag/GreatSQL-8.0.32-26 用户手册&#xff1a;https://greatsql.cn/docs…

【知识专栏丨python数分实战】天猫订单数据分析及可视化|taobao天猫订单接口

今天这篇文章将给大家介绍天猫订单数据分析及可视化案例。 import pandas as pdimport numpy as npfrom pyecharts.charts import Pie,Bar,Line,Map,Map3D,Funnelfrom pyecharts import options as optsimport matplotlib.pyplot as pltimport warningsimport seaborn as snsfr…

《刚刚问世》系列初窥篇-Java+Playwright自动化测试-7-元素基础定位方式-下篇 (详细教程)

软件测试微信群&#xff1a;https://bbs.csdn.net/topics/618423372 有兴趣的可以扫码加入 1.简介 上一篇主要是讲解我们日常工作中在使用Playwright进行元素定位的一些比较常用的基础定位方式的理论基础知识以及在什么情况下推荐使用。今天这一篇讲解和分享一下剩下部分的基…

重塑未来体验:边缘计算与云原生的完美邂逅

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《未来已来&#xff1a;云原生之旅》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、云原生的兴起 2、边缘计算的兴起 二、边缘计算基础 …

LoadRunner12 添加事务并添加检查点

1、先要添加事务开始函数lr_start_transaction("登陆事务");&#xff0c;在接口上方右击点击-插入-开始事务。输入事务名称&#xff1b; 2、在某个接口想法 右击点击-插入-结束事务&#xff0c;输入事务名称&#xff0c;与开始事务名称要保持一致&#xff0c;lr_end_…

springboot自动装配(源码分析)

利用spi机制发现配置类并注册到spring容器中 以下示例使用springboot:3.2.1版本 相关注解 SpringBootApplication EnableAutoConfiguration AutoConfigurationImportSelector 使用Import导入AutoConfigurationImportSelector&#xff0c;随着springboot启动&#xff0c;会…

工业控制常用的EtherNet/IP、OPC UA协议的标签数据转发到另外的PLC寄存器地址

在工业自动化领域&#xff0c;越来越多的碰到标签方式通讯的设备&#xff0c;常用有CIP(基于EtherNet/IP) 的协议、OPCUA协议等&#xff0c;CIP协议主要是罗克韦尔/AB的PLC、欧姆龙NX/NJ系列的PLC等&#xff0c;OPCUA协议常见于工业机器人、智能焊接设备等。在不具备标签协议接…

AI绘画变现也有新思路,国风带你日进斗金!

在中国的文化传承中&#xff0c;古典的风韵总是能引发无尽的遐想和美感。 在现代化的今天&#xff0c;越来越多的人开始重新审视和欣赏那些古老的中国风&#xff0c;发现其中蕴含的深厚文化底蕴与无与伦比的美感。 特别是在影视、音乐、舞蹈等艺术形式中&#xff0c;国风元素…

【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值

C语法相关知识点可以通过点击以下链接进行学习一起加油&#xff01;命名空间缺省参数与函数重载 本章将分享C增加的几种常见特性&#xff0c;主要内容为引用与内联函数 | auto关键字与for循环 | 指针空值&#xff0c;这些知识看似很多&#xff0c;实际也不少。本章篇幅长&#…

双笼转子三相感应电动机瞬态分析(7):定子绕组短路故障分析

1. 引言 2. 定子绕组短路时端电压约束条件 3. 双笼转子三相感应电动机数学模型 4. 仿真分析 5. 结论 6. 参考文献 1. 引言 定子绕组短路故障是三相感应电动机的典型故障情形之一&#xff0c;但其发生几率比缺相故障要低。根据电力系统的研究报告&#xff0c;单相短路在所有…

在仪器计量校准中,无尘车间洁净室检测有哪些方法和流程?

仪器计量校准行业内&#xff0c;无尘车间洁净室检测可以说是较为热门的业务&#xff0c;因为其预算高&#xff0c;且检测流程不是太繁琐&#xff0c;很多仪器计量校准机构也是设立相关实验室&#xff0c;专门处理相关仪器的检测。不过虽然许多机构想要涉足该领域&#xff0c;但…

ArcGIS自带的python安装第三方库

ArcGIS自带的python安装第三方库 文章目录 ArcGIS自带的python安装第三方库pip库安装安装setuptools库安装pip库 第三方库安装 在做项目时&#xff0c;用到了ArcGIS(非pro)中python中的arcpy库&#xff0c;但是又依赖其他外部库&#xff0c;而 Python2并不像Python3那样自带pip…