【优选算法】位运算

在这里插入图片描述

目录

  • 常见位运算总结
    • 1、基础位运算
    • 2、给一个数n,确定它的二进制位的第x位上是0还是1
    • 3、将一个数n的二进制位的第x位改成1
    • 4、将一个数n的二进制位的第x位改成0
    • 5、位图的思想
    • 6、提取一个数n的二进制位中最右侧的1
    • 7、将一个数n的二进制位中最右侧的1变为0
    • 8、位运算的优先级
    • 9、异或(^)运算的运算律
  • 一、[位1的个数](https://leetcode.cn/problems/number-of-1-bits/description/)
  • 二、[比特位计数](https://leetcode.cn/problems/counting-bits/description/)
  • 三、[汉明距离](https://leetcode.cn/problems/hamming-distance/description/)
  • 四、[只出现一次的数字](https://leetcode.cn/problems/single-number/description/)
  • 五、[只出现一次的数字 III](https://leetcode.cn/problems/single-number-iii/description/)
  • 六、[判定字符是否唯一](https://leetcode.cn/problems/is-unique-lcci/description/)
  • 七、[丢失的数字](https://leetcode.cn/problems/missing-number/description/)
  • 八、[两整数之和](https://leetcode.cn/problems/sum-of-two-integers/description/)
  • 九、[只出现一次的数字 II](https://leetcode.cn/problems/single-number-ii/description/)
  • 十、[消失的两个数字](https://leetcode.cn/problems/missing-two-lcci/description/)
  • 结尾

常见位运算总结

1、基础位运算

左移操作符 >> 、右移操作符 << 、按位取反 ~ ,这三个操作符我不做讲解。

接下来讲解3个操作符以及它使用方法对应的记忆方法

按位与:& 有0就是0
按位或:| 有1就是1
按位异或:^ 相同为0相异为1/无进位相加
在这里插入图片描述


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

首先我们认为一个整数有32位、它最低位是0位,它的最高位为31位,那么就可以使用(n >> x)&1的操作来判断这个数的第x位是0还是1,因为n>>x能够将数字n上的第x位移动到第0位,1除了第0位上是1,其他位都是0,异或后结果只会出现第0位上为0/1其他位为0的情况,所以结果是0则数n二进制位的第x位上是0,是1则数n二进制位的第x位上是1。

在这里插入图片描述


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

首先我们认为一个整数有32位、它最低位是0位,它的最高位为31位,那么就可以使用n|=(1<<x)的操作将数字n的二进制位的第x位改成1。1<<x能够将1的第x位变为1,异或后无论n上的第x位上是0是1都会变为1。

在这里插入图片描述


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

首先我们认为一个整数有32位、它最低位是0位,它的最高位为31位,那么就可以使用n&=(~(1<<x))的操作将数字n的二进制位的第x位改成0。1<<x能够将1的第x位变为1,按位与后除了第x位上为0其他位上都为1,再与n按位与后,n中的第x位都会被0变为1,其他位都是与1按位与,则都不变。

在这里插入图片描述


5、位图的思想

位图的本质就是哈希表,我们在之前就学习过哈希表,哈希表很多情况下是数组,假设是一个int类型的数组,可以通过在数组中存储某些数组来表示某些意义,现在我们可以通过变量的比特位来表示某些信息,假设一个int类型的变量,一个int类型的变量有32位,其中的每一位存储的0/1都可以分别表示某种信息。

在这里插入图片描述


6、提取一个数n的二进制位中最右侧的1

首先我们认为一个整数有32位、它最低位是0位,它的最高位为31位,那么就可以使用n&-n的操作提取一个数n的二进制位中最右侧的1。这里的-n也就~n+1,-n能够将最右侧1的左侧所有二进制数字变成相反的,+1能将右侧所有二进制数字变为0,按位与后就只剩下最右侧的1。
在这里插入图片描述


7、将一个数n的二进制位中最右侧的1变为0

首先我们认为一个整数有32位、它最低位是0位,它的最高位为31位,那么就可以使用n&(n-1)的操作将一个数n的二进制位中最右侧的1变为0。-1能够将数字n最右侧1的左侧二进制数字变成相反的(包括它本身),按位与后右侧不变,左侧都不同则都变为0,就可将最右侧的1变为1。

在这里插入图片描述


8、位运算的优先级

位运算的优先级大家可以在其他文章中查看,这里建议大家能加括号就加括号。


9、异或(^)运算的运算律

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

一、位1的个数

题目描述
在这里插入图片描述

思路讲解
在上面常见位运算总结中讲到了如何将一个数的二进制位中最右侧的1修改为0,我们只需要重复这个操作,并记录这个操作的次数,当这个数变为0以后,操作次数就是这个数二进制位中1的个数。

编写代码

class Solution {
public:
    int hammingWeight(int n) {
        int count = 0;
        while(n > 0)
        {
            // 去掉最右侧的一
            n &= (n - 1);
            count++;
        }
        return count;
    }
};

二、比特位计数

题目描述
在这里插入图片描述

思路讲解
这题的思路与上一题的思路一致,只是上一题是获取一个数的二进制位中有多少个1,而本题是获取n个数的二进制位中有多少个1,本质上是一样的,这里不做过多讲解。

编写代码

class Solution {
public:
    int hammingWeight(int n) {
        int count = 0;
        while(n > 0)
        {
            // 去掉最右侧的1
            n &= (n - 1);
            count++;
        }
        return count;
    }

    vector<int> countBits(int n) {
        vector<int> ans;
        for(int i = 0 ; i <= n ;i++)
            ans.push_back(hammingWeight(i));

        return ans;
    }
};

三、汉明距离

题目描述
在这里插入图片描述

思路讲解
两个整数之间的 汉明距离 指的是这两个数字对应二进制位不同的位置的数目。所以我们只需要将两个数每个对应的二进制位上的数字获取并对比,记录
二进制位不同的位置的数目即可,我们在上面讲到过可以使用(n >> x)&1的操作获取一个数的第x位上的二进制是0还是1。

编写代码

class Solution {
public:
    int hammingDistance(int x, int y) {
        int count = 0;
        for(int i = 0 ; i <= 31 ;i++)
        {
            if(((x >> i) & 1) != (((y >> i) & 1)))
                count++;
        }

        return count;
    }
};

四、只出现一次的数字

题目描述
在这里插入图片描述

思路讲解
在上面异或运算的运算律中我们讲到过a^a=0a^0=a,本题中除了一个数只出现过一次,其他数都出现过两次,将所有的数异或在一起,出现过两次的数全部异或到一起就是0,出现过一次的数与0异或就是我们需要的结果。

编写代码

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int val = 0;
        for(auto ch : nums)
        {
            val ^= ch;
        }
        return val;
    }
};

五、只出现一次的数字 III

题目描述
在这里插入图片描述
思路讲解

在上面异或运算的运算律中我们讲到过a^a=0a^0=a,本题中除了两个数只出现过一次,其他数都出现过两次,将所有的数异或在一起,就是两个只出现一次的数相异或的结果。两个数异或的结果的二进制位上有1就代表着两个数在当前位上一定是不同的,我们可以将两数异或结果上某一个1的位置标记,记为pos,将所以pos位上为1的数全部异或在一起,就能够得到其中一个答案,再将两数异或的结果与刚刚得到的一个答案异或,就能够得到另一个答案。

编写代码

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        vector<int> v;
        v.resize(2 , 0);
        int xor1 = 0;
        // 将所有数异或,可以得到需要的两个数的异或
        for(auto x : nums)
        {
            xor1 ^= x;
        }
        // 我们知道,异或后的二进制位上的 1,
        // 必定是两个数对应二进制位上的一个,且只有一个 
        // 那我们只需要将某一位上的1的位置记录下来
        // 并且将数组遍历一遍,将这个位置上为1的数全部异或就能得到第一个数
        // 再将第一步中两个数的异或值与第一个数异或就能得到第二个数
        int pos = 0;
        for(int i = 0 ; i < 32 ;i++)
        {
            if( ((xor1 >> i) & 1 ) == 1 )
            {
                pos = i;
                break;
            }

        }
        for(int i = 0 ; i < nums.size() ; i++)
        {
            if(((nums[i] >> pos) & 1) == 1)
            {
                v[0] ^= nums[i];
            }
        }
        v[1] = xor1 ^ v[0];

        return v;
    }
};

六、判定字符是否唯一

题目描述
在这里插入图片描述

思路讲解
本题最简单的思路就是建立一个数组,将每个字母出现的次数记录下来,当有一个字符出现两次就返回false,但是这样需要花费4*26个字节,而使用位图则只需要4个字节,一个int类型的变量就有32个比特位,将26位小写字母对应到其中的32个比特位中,当遍历到一个字符的时候,就查看对应比特位上是0/1,如果是1就返回false,是0就继续遍历字符串。

本题还有一个优化方案就是雀巢原理,小写字母一共有26个,当字符串的长度超过26时,说明一定有一个字母是出现过两次的。

编写代码

class Solution {
public:
    bool isUnique(string astr) {
        // 优化 雀巢原理
        if(astr.size() > 26)
            return false;
        
        // 因为小写字母只有26个
        // 而int中有32个比特位
        // 那么这里使用位图来解决问题
        int tmp = 0;
        for(auto e : astr)
        {
            if(((tmp >> (e - 'a')) & 1) == 1)
                return false;
            else
                tmp |= (1 << (e - 'a'));
        }
        return true;
    }
};

七、丢失的数字

题目描述
在这里插入图片描述

思路讲解
本题最简单的思路就是建立一个大小为n的数组arr,遍历nums并在arr中标记,当nums遍历完后,再遍历arr查看哪个数字没有被标记就是答案,但是这个方法的缺点就是需要使用额外的空间复杂度。

还有可以使用高斯求和,得到0到n之间的数相加后的结果,减去nums中数组中所有数,就是本题的答案。

还可以使用位运算,上课讲到过a^a=0a^0=a,将0到n中所有的数异或,再与nums数组中所有的数异或,就能够得到本题的答案。使用位运算可以将本题转化为上面只出现一次的数字的那道题。

编写代码

class Solution {
public:
    int missingNumber(vector<int>& nums) {
        int ans = 0;
        int numsLen = nums.size();
        for(int i = 0 ; i <= numsLen ;i++)
            ans ^= i;
        
        for(auto e : nums)
            ans ^= e;
        
        return ans;
    }
};

八、两整数之和

题目描述
在这里插入图片描述

思路讲解

我们在记忆按位异或使用的时候,按位异或就是无进位相加,那么这里只缺少进位,进位我们可以通过按位与获得,但是需要注意的是获得的进位需要向左侧移动一位。我们将按位异或得到的无进位相加的结果记为tmp1,将按位与获得的进位记为tmp2,持续将tmp1与tmp2按位异或和按位与得到无进位相加与进位,只要当进位tmp2为0时,tmp1就是结果。

在这里插入图片描述

编写代码

class Solution {
public:
    int getSum(int a, int b) {
        int tmp1 = (a & b)<<1;  // 两数按位与后向右移动一位,代表着进位
        int ans = a ^ b;        // 两数异或代表无进位相加
        while(tmp1 != 0)
        {
            int tmp2 = tmp1;    // 记录tmp1
            tmp1 = (tmp1 & ans)<<1; 
            ans ^= tmp2;
        }
        return ans;
    }
};

九、只出现一次的数字 II

题目描述
在这里插入图片描述

思路讲解
题目中讲到了有一个数只出现过一次,其他的数都出现了三次,那么将所有数的二进制位罗列出来,那么将所有数对应每一位相加起来会出现两种情况:3n与3n+1,通过将3n与3n+1进行%3,就能得到0和1的结果,这里得到的1就是只出现过一次的数字对应比特位上的1,只需要将这些1组合到对应的比特位上,得到的数字就是结果。

同理给你一个整数数组 nums ,除某个元素仅出现一次外,其余每个元素都恰出现n次,都可以使用这个方法。

编写代码

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int sum = 0;       // 记录所有数字某个二进制位的和
        int num = 0;       // 记录答案
        for(int i = 0 ; i < 32 ; i++)
        {
            for(int ch : nums)
            {
                // 将第i个位置上的二进制数字取出来相加
                sum += ((ch >> i)&1);
            }
            if(sum % 3 != 0)
            {
                num |= (1 << i);
            }
            sum = 0;
        }
        return num;
    }
};

十、消失的两个数字

题目描述
在这里插入图片描述

思路讲解
本道题就是上面只出现一次的数字III和丢失的数字两道题的结合,只需要找到丢失两个数的按位异或的结果就可以使用只出现一次的数字III中的思路,分别得到两个数是哪两个数,这里就不做讲解。

编写代码

class Solution {
public:
    vector<int> missingTwo(vector<int>& nums) {
        int tmp = 0;
        int numsLen = nums.size();
        for(int i = 1 ; i <= numsLen + 2; i++)
            tmp ^= i;
        
        for(auto e : nums)
            tmp ^= e;
        
        int lowbit = (tmp & -tmp);
        int ans1 = tmp;

        for(int i = 1 ; i <= numsLen + 2; i++)
            if((lowbit & i) == lowbit)
                ans1 ^= i;

        for(auto e : nums)
            if((lowbit & e) == lowbit)
                ans1 ^= e; 
            
        int ans2 = (tmp ^ ans1);

        return {ans1,ans2};
    }
};

结尾

如果有什么建议和疑问,或是有什么错误,大家可以在评论区中提出。
希望大家以后也能和我一起进步!!🌹🌹
如果这篇文章对你有用的话,希望大家给一个三连支持一下!!🌹🌹

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

systemverilog约束中:=和:/的区别

“x dist { [100:102] : 1, 200 : 2, 300 : 5}” 意味着其值等于100或101或102或200或300其中之一&#xff0c; 其权重比例为1:1:1:2:5 “x dist { [100:102] :/ 1, 200 : 2, 300 : 5}” 意味着等于100&#xff0c;101&#xff0c;102或200&#xff0c;或300其…

06_数据类型

数据类型 数据类型分类 JavaScript 语言的每一个值,都属于某一种数据类型。JavaScript 的数据类型,共有六种。(ES6 又新增了第七种 Symbol 类型的值和第八种 BigInt类型,当前课程暂不涉及) 据类型分类 原始类型(基础类型) var age = 20, var name = 尚学堂"; var le…

芯盾时代的身份安全产品体系

芯盾时代具备全栈零信任身份安全产品和服务能力&#xff1a; 芯盾时代IAM能够适配大企业用户复杂的应用访问需求&#xff0c;提供云端、互联网端、企业内网全场景的身份访问安全接入能力&#xff1b; 芯盾时代IAM能够理解大企业用户的身份差异&#xff0c;为内部用户、合作方和…

【Db First】.NET开源 ORM 框架 SqlSugar 系列

.NET开源 ORM 框架 SqlSugar 系列 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列【Code First】.NET开源 ORM 框架 SqlSugar 系列 &#x1f…

shell综合

声明&#xff01; 学习视频来自B站up主 泷羽sec 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&#…

Ubutuns服务器搭建与维护

1.靶机搭建 首先&#xff0c;安装 Apache2 作为 Web 服务器&#xff1a; sudo apt install apache2 安装完成后&#xff0c;可以启动 Apache 服务并确保它开机自启&#xff1a; sudo systemctl start apache2 sudo systemctl enable apache2然后&#xff0c;你可以通过访问…

003 LVGL相关文件分析

LVGL移植相关文件&#xff1a; 显示设备接口文件 lv_port_disp_templ.c/输入设备接口文件 lv_port_indev_templ.c/h 裁剪、配置文件 lv_conf.h lv_conf.h文件内容介绍&#xff1a; 对应中文翻译版本&#xff1a; #if 1 /* 设置为1&#xff0c;以启…

阿里巴巴即将超越OpenAI的o1?

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Web自动化测试教程详解(附文档一份)

一、什么是web自动化测试 自动化&#xff08;Automation&#xff09;是指机器设备、系统或过程&#xff08;生产、管理过程&#xff09;在没有人或较少人的直接参与下&#xff0c;按照人的要求&#xff0c;经过自动检测、信息处理、分析判断、操纵控制&#xff0c;实现预期的目…

外包干了两年,快要废了。。。

先说一下自己的情况&#xff0c;普通本科&#xff0c;曾在外包干了2年多的功能测试&#xff0c;再加上大环境不好&#xff0c;那时我整个人心惊胆战的&#xff0c;怕自己卷铺盖走人了&#xff0c;所以当时我感觉自己不能够在这样蹉跎下去了&#xff0c;长时间呆在一个舒适的环境…

乌班图单机(不访问外网)部署docker和服务的方法

面向对象:Ubuntu不能访问外网的机子,部署mysql、redis、jdk8、minio 过程: 1、安装docker(照着图去这里找对应的下载下来https://download.docker.com/linux/static/stable/),将7个docker官网下载的文件下载下来后,传上去服务器随便一个文件夹或者常用的opt或者/usr/lo…

【线程】Java多线程代码案例(2)

【线程】Java多线程代码案例&#xff08;2&#xff09; 一、定时器的实现1.1Java标准库定时器1.2 定时器的实现 二、线程池的实现2.1 线程池2.2 Java标准库中的线程池2.3 线程池的实现 一、定时器的实现 1.1Java标准库定时器 import java.util.Timer; import java.util.Timer…

pyspark实现基于协同过滤的电影推荐系统

最近在学一门大数据的课&#xff0c;课程要求很开放&#xff0c;任意做一个大数据相关的项目即可&#xff0c;不知道为什么我就想到推荐算法&#xff0c;一直到着手要做之前还没有新的更好的来代替&#xff0c;那就这个吧。 推荐算法 推荐算法的发展由来已久&#xff0c;但和…

log4c库使用

log4c库 介绍 log4c 是一个 C 语言实现的日志库&#xff0c;它是 log4j&#xff08;Java 语言的日志框架&#xff09;的 C 语言版本&#xff0c;旨在为 C 语言应用程序提供灵活、可配置的日志功能。log4c 提供了丰富的日志功能&#xff0c;包括日志级别、日志输出目标、日志格…

Llmcad: Fast and scalable on-device large language model inference

题目&#xff1a;Llmcad: Fast and scalable on-device large language model inference 发表于2023.09 链接&#xff1a;https://arxiv.org/pdf/2309.04255 声称是第一篇speculative decoding边缘设备的论文&#xff08;不一定是绝对的第一篇&#xff09;&#xff0c;不开源…

Leetcode 每日一题 36.有效的数独

目录 问题描述 输入输出格式 算法思路 过题图片 代码实现 题目链接 复杂度分析 问题描述 给定一个 9x9 的数独棋盘&#xff0c;我们需要判断棋盘上已填入的数字是否有效。根据数独的规则&#xff0c;有效性需要满足以下条件&#xff1a; 数字 1-9 在每一行只能出现一次…

深入浅出UART驱动开发与调试:从基础调试到虚拟驱动实现

往期内容 本专栏往期内容&#xff1a;Uart子系统 UART串口硬件介绍深入理解TTY体系&#xff1a;设备节点与驱动程序框架详解Linux串口应用编程&#xff1a;从UART到GPS模块及字符设备驱动 解UART 子系统&#xff1a;Linux Kernel 4.9.88 中的核心结构体与设计详解IMX 平台UART驱…

韦东山stm32hal库--定时器喂狗模型按键消抖原理+实操详细步骤

一.定时器按键消抖的原理: 按键消抖的原因: 当我们按下按键的后, 端口从高电平变成低电平, 理想的情况是, 按下, 只发生一次中断, 中断程序只记录一个数据. 但是我们使用的是金属弹片, 实际的情况就是如上图所示, 可能会发生多次中断,难道我们要记录3/4次数据吗? 答:按键按下…

Web前端学习_CSS盒子模型

content padding border margin <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>CSS盒子模型</title><style></style> </head> <body> <div class"demo&quo…

将自定义 AWS S3 快照存储库连接到 Elastic Cloud

作者&#xff1a;来自 Elastic Annie Hansen, Stef Nestor 在本博客中&#xff0c;我们将介绍如何通过 Elasticsearch 的快照将我们已提交的集群数据备份到 AWS S3 存储桶中。在 Elastic Cloud&#xff08;企业版&#xff09;中&#xff0c;Elastic 在其 found-snapshots 存储…