位运算的奇技淫巧

news2024/9/22 1:43:34

常见位运算总结:

1、基础位运算

左移<<运算

将二进制数向左移位操作,高位溢出则丢弃,低位补0。

右移>>运算

右移位运算中,无符号数和有符号数的运算并不相同。对于无符号数,右移之后高位补0;对于有符号数,符号位一起移动,正数高位补0,负数高位补1

按位与&运算

有0就是0,巧计:&这个符号像是有两个0组合而成。

按位或 | 运算

有1就是1,巧计:|本身就像一个1

按位异或^运算(两种解释方法)

相同为0,相异为1,或者解释成无进位相加

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

(n >> x) & 1

&1后的结果就是0/1,因为1的二进制位除了最后一位,其他都是0,&0就是0

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

n =(1 << x)|  n

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

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

5、位图的思想

本质上就是一个哈希表

6、提取一个数(n)二进制表示中最右侧的1(lowbit

n & -n

解释:-n的操作就是先取反,然后再+1,这样造成的影响是最右边的1前面都是n的相反数,这样再跟原先的n&,因为是相反数,所以有一方肯定是0,这样最右边的1前面的数字都变成了0,最右边1右边本身就是0。

7、干掉一个数(n)最右边的1

n &(n - 1)

8、位运算的优先级

为了避免记住闲杂的公式,我们只需要记住能加括号就加括号。

9、异或运算的运算规律

  • a ^ 0 = a
  • a ^ a = 0(消消乐)
  • a ^ b ^ c = a ^ (b ^ c)

上面的指示是位运算的基础知识,下面就带着上面的指示开始实操啦

第一题:
191. 位1的个数

编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 '1' 的个数(也被称为汉明重量)。

解析:

只需要每次右移&1判断是否为1。

原码:

class Solution {
public:
    int hammingWeight(uint32_t n) {
        int sum = 0;
        int ret = n;
        for(int i = 0;i<32;i++)
        {
            if(ret & 1 == 1) sum++;
            ret = ret >> 1;
        }
        return sum;
    }
};

第二题、461. 汉明距离

两个整数之间的 汉明距离 指的是这两个数字对应二进制位不同的位置的数目。

给你两个整数 x 和 y,计算并返回它们之间的汉明距离。

解析:

根据题目来看,可能最先想到的就是异或操作,相同为 0,不同为 1。异或操作后结果为 0101,然后我们只需要统计出来二进制结果中 1 的个数就可以计算出来汉明距离啦。

原码:

class Solution {
public:
    int hammingDistance(int x, int y) {
        int ret = x ^ y;
        int sum = 0;
        //计算1的个数
        for(int i = 0;i<32;i++)
        {
            if(ret & 1 == 1) sum++;
            ret = ret >> 1;
        } 
        return sum;
    }
};

第三题、136. 只出现一次的数字

给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。

解析:

这是一道很典型的运用^的题目,我们只需要理解异或运算符,这题就迎刃而解啦。

原码:

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

第四题、260. 只出现一次的数字 III

给你一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。

你必须设计并实现线性时间复杂度的算法且仅使用常量额外空间来解决此问题。

解析:

本题是上一题的升级版,

把nums中的元素全部异或起来的结果eor就是那两个只出现一次的数字的异或结果。而这两个数不相同,意味着eor至少有一位是1,我们可以用lowbit运算拿到最低位的1,然后遍历nums数组,将所有数nums[i]按照这一位是不是1分成两类,初始化num1=num2=0

  1. 如果当前位是1,就将nums[i]异或到num1​上。

  2. 如果当前位是0,就将nums[i]异或到num2​上。

这样一来,两个只出现一次的数就会被分别异或到num1​和num2​上,而其他数也会被分别异或到这两个数上。而由于其他数都出现了两次,所以最终它们就会被异或成0,num1​和num2​就是那两个只出现一次的数。

注意进行位运算的优先级,直接加上括号就好!!!

原码:

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        int a = 0, b = 0;//记录两个不同的数
        int ret = 0;
        for(int i = 0;i<nums.size();i++)
            ret ^= nums[i];
        //进行lowbit运算,两者不同,二进制肯定有1
        int tmp = ret & (-(long long)ret);//防止数据溢出
        for(int i = 0;i<nums.size();i++)
        {
            if((tmp & nums[i]) == 0)//注意优先级! 
                a ^= nums[i];
            else b ^= nums[i];
        }
        return {a,b};
    }
};

第五题、面试题 01.01. 判定字符是否唯一

解析:

本题第一思想直接用哈希表解决,但题目中用说尽量不用数据结构,我们可以尝试用位图解决!

用位图解决,需要熟练掌握位运算技巧,对巩固位运算有很大帮助!

原码:

class Solution {
public:
    bool isUnique(string astr) {
        int bitmap = 0;//用位图思想解决
        int tmp = 0;
        int n = astr.size();
        //利用鸽巢原理优化
        if(n > 26) return false;
        for(int i = 0;i<astr.size();i++)
        {
            tmp = astr[i] - 'a';
            //判断字符是否已经出现过
            if(((bitmap >> tmp) & 1) == 1) return false;
            //把当前字符加入位图中
            bitmap = bitmap | (1 << tmp);
        }
        return true;
    }
};

第六题、371. 两整数之和

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

思路:

我们前面介绍了^运算的另一个功能是不进位相加,因此我们可以利用这个特性去解决这道题。

因为是不进位,所以我们要想办法去解决进位的问题,^运算是相同为0,相异为1,相异不可能进位,只有相同并且都是1的情况下,才会进位,因此我们直接&,查找出都是1,因为是进位,所以还要左移一位,(a & b)<< 1,然后分别重制a,b的值。

原码:

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

第七题、137. 只出现一次的数字 II

给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。

你必须设计并实现线性时间复杂度的算法且使用常数级空间来解决此问题。

解析:

本题有点难度,两层嵌套循环,根据32位int,把每个数位相加再对3取的余数即可,将每个数想象成32位的二进制,对于每一位的二进制的1和0累加起来必然是3N或者3N+1, 为3N代表目标值在这一位没贡献,3N+1代表目标值在这一位有贡献(=1),然后将所有有贡献的位|起来就是结果。这样做的好处是如果题目改成K个一样,只需要把代码改成cnt%k,很通用~

原码:

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ans = 0;
        int n = nums.size();
        for(int i = 0;i<32;i++)//依次去修改ans的每一位
        {
            int sum = 0;
            for(int j = 0;j<n;j++)
            {
                //计算nums中所有数的第i位的和
                sum += (nums[j] >> i) & 1;
            }
            //把第i位修改
            if(sum % 3)   
                ans ^= (1 << i); 
        }
        return ans;
    }
};

第八题、面试题 17.19. 消失的两个数字

给定一个数组,包含从 1 到 N 所有的整数,但其中缺了两个数字。你能在 O(N) 时间内只用 O(1) 的空间找到它们吗?

以任意顺序返回这两个数字均可。

解析:

本题是两道题的融合版。

  • 将所有的数异或在一起,记为tmp
  • 找到tmp中,比特位上为1的那一位
  • 根据不同的那一位,划分为两类异或

原码

class Solution {
public:
    vector<int> missingTwo(vector<int>& nums) {
        int a = 0,b = 0;
        int n = nums.size();
        int ret = 0;
        //先将所有数异或
        for(int i = 1;i<=n+2;i++)
            ret ^= i;
        for(int i = 0;i<n;i++)
            ret ^= nums[i];
        //lowbit运算找到最右边的1
        int tmp = ret & (-(long long)ret);//防止溢出
        for(int i = 0;i<n;i++)
        {
            if((nums[i] & tmp) == 0) a ^= nums[i];
            else b ^= nums[i];
        }
        for(int i = 1;i<=n+2;i++)
        {
            if((i & tmp) == 0) a ^= i;
            else b ^= i; 
        }
        return {a,b};
    }
};

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

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

相关文章

软件测试|Python字典的访问方式你了解吗?

简介 Python中的字典&#xff08;dictionary&#xff09;是一种非常有用的数据结构&#xff0c;它允许您存储键-值对&#xff0c;从而可以快速查找、插入和删除数据。本文将详细介绍如何访问字典中的数据&#xff0c;包括基本访问、循环遍历、使用内置方法以及处理不存在的键等…

Redis持久化和集群架构

目录 Redis持久化 RDB快照&#xff08;snapshot&#xff09; RDB优点 RDB缺点 RDB的触发机制 AOF持久化 AOF文件重写 AOF触发机制 混合模式 Redis主从架构 Redis哨兵高可用架构 Redis Cluster架构 槽位定位算法 跳转重定位 Redis集群节点间的通信机制 Redis持久化…

centos安装主从mysql集群

在 CentOS 系统上安装和配置 MySQL 主从复制环境的步骤与 Debian/Ubuntu 系统有所不同。以下是在 CentOS 系统上进行配置的详细步骤&#xff1a; 步骤 1&#xff1a;在主服务器上安装和配置 MySQL&#xff08;10.206.0.13&#xff09; 安装 MySQL 服务器: 首先&#xff0c;添加…

NeRF资料整理

文章目录 1.NeRF原理讲解2.NeRF中用到的NDC空间坐标系3.NeRF中的sample_pdf概率采样函数 1.NeRF原理讲解 nerf 原理讲解&#xff1a;这个视频对NeRF中体渲染公式的讲解和推导非常好&#xff0c;言简意赅&#xff0c;而且和论文、代码都可以对应上。 2.NeRF中用到的NDC空间坐标…

【AI】ChatGPT和文心一言那个更好用

大家好&#xff0c;我是全栈小5&#xff0c;欢迎阅读文章&#xff01; 此篇是【话题达人】序列文章&#xff0c;这一次的话题是《自然语言处理的发展》 文章将以博主的角度进行讲述&#xff0c;理解和水平有限&#xff0c;不足之处&#xff0c;望指正。 目录 背景自我介绍面试题…

linux 定时任务 crontab 使用笔记

最近在服务器上跑撸茅台的脚本&#xff0c;需要使用定时任务每天早上9点准时预约一次抢茅台的脚本&#xff0c;因此需要用到 crontab 命令。crontab主要是用于设置周期性执行命令&#xff0c;比如每分钟、每小时或者每周执行一个固定的命令&#xff0c;该命令从标准输入设备读取…

靶场实战(18):OSCP备考之VulnHub MY CMSMS

打靶思路 资产发现 主机发现服务发现漏洞发现&#xff08;获取权限&#xff09; 80端口/HTTP服务 组件漏洞URL漏洞3306端口/MySQL服务 组件漏洞口令漏洞80端口/HTTP服务 URL漏洞URL漏洞提升权限 www-data用户 sudosuidcron内核提权信息收集armour用户 sudo 1、资产发现 1.1…

Pytest系列(2) - assert断言详细使用

前言 与unittest不同&#xff0c;pytest使用的是python自带的assert关键字来进行断言assert关键字后面可以接一个表达式&#xff0c;只要表达式的最终结果为True&#xff0c;那么断言通过&#xff0c;用例执行成功&#xff0c;否则用例执行失败 assert小栗子 想在抛出异常之…

基于ssm+vue的宠物医院系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目背景…

01 MyBatisPlus快速入门

1. MyBatis-Plus快速入门 版本 3.5.31并非另起炉灶 , 而是MyBatis的增强 , 使用之前依然要导入MyBatis的依赖 , 且之前MyBatis的所有功能依然可以使用.局限性是仅限于单表操作, 对于多表仍需要手写 项目结构&#xff1a; 先导入依赖&#xff0c;比之前多了一个mybatis-plus…

肌营养不良患者生活质量的“提升”

肌营养不良患者基本上是生活无法自理的&#xff0c;那么作为肌营养不良患者的家属&#xff0c;提升病人的生活质量就迫在眉睫。看了这篇文章你就知道该怎么做了。 ①保持生活环境整洁 肌营养不良患者本身体质较弱&#xff0c;而且后期会卧病在床&#xff0c;为了防止并发症的发…

【机组】算术逻辑单元带进位运算实验的解密与实战

​&#x1f308;个人主页&#xff1a;Sarapines Programmer&#x1f525; 系列专栏&#xff1a;《机组 | 模块单元实验》⏰诗赋清音&#xff1a;云生高巅梦远游&#xff0c; 星光点缀碧海愁。 山川深邃情难晤&#xff0c; 剑气凌云志自修。 ​ 目录 &#x1f33a;一、 实验目…

Python初识——小小爬虫

一、找到网页端url 打开浏览器&#xff0c;打开百度官方网页点击图片&#xff0c;打开百度图片 鼠标齿轮向下滑&#xff0c;点击宠物图片 进入宠物图片网页&#xff0c;在网页空白处点击鼠标右键&#xff0c;弹出的框中最下方显示“检查”选项&#xff0c;点击&#xff08;我是…

AIGC - 视频生成模型的相关算法进展

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/135688206 视频生成技术确实是一个很有潜力的颠覆性技术领域&#xff0c;可以作为企业创新梯队的重点关注方向&#xff0c;最近发展很快&#xff…

使用 FFmpeg 轻松调整视频的大小/缩放/更改分辨率

在此 FFmpeg 教程中&#xff0c;我们学习使用 FFmpeg 的命令行工具更改视频的分辨率&#xff08;或调整视频的大小/缩放&#xff09;。 更改视频的分辨率&#xff08;也称为调整大小或缩放&#xff09;是视频编辑、处理和压缩中非常常见的操作。对于 ABR 视频流尤其如此&#…

激光无人机打击系统——光束控制和指向系统

激光无人机&#xff08;UAV&#xff09;打击系统中的光束控制和指向系统通常包括以下几个关键组件和技术&#xff1a; 激光发射器&#xff1a;这是系统的核心&#xff0c;负责生成高能量的激光束。常用的激光类型包括固体激光器、化学激光器、光纤激光器等&#xff0c;选择取决…

组件(Component):可重用的元素

目标效果&#xff1a;点击粉色按钮后&#xff0c;出现一行“为什么非要点我&#xff1f;”的文字。 用组件的方式实现&#xff1a;首先单击项目文件夹01&#xff0c;然后右键弹窗中点击“添加新文件” 。 选择 QML File 文件&#xff1a; 文件名就叫Button&#xff0c;然后把代…

基于springboot+vue摄影分享管理系统

摘要 摄影分享管理系统是一款全栈应用&#xff0c;采用了Spring Boot和Vue.js作为技术基础。旨在为摄影爱好者提供便捷而强大的平台&#xff0c;用户可以在这里展示、分享和管理自己的摄影作品。系统具备完善的用户管理功能&#xff0c;包括注册、登录和个人信息编辑&#xff0…

css 3D立体动画效果怎么转这个骰子才能看到5

css 3D立体动画效果怎么转这个骰子才能看到5 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equ…

【C++】unordered_map,unordered_set模拟实现

unordered_map&#xff0c;unordered_set模拟实现 插入普通迭代器const迭代器unordered_map的[ ]接口实现查找修改哈希桶完整代码unordered_map完整代码unordered_set完整代码 喜欢的点赞&#xff0c;收藏&#xff0c;关注一下把&#xff01; 上一篇文章我们把unordered_map和u…