算法:图解位运算以及鸽巢原理应用

news2025/1/30 16:26:00

文章目录

  • 实现原理
    • 基础位运算
    • 位图思想
    • 找最右侧数
    • 按位异或
  • 算法思路
  • 典型例题
    • 基础位运算
      • 只出现一次的数字
      • 只出现一次的数字III
    • 经典题型
      • 判断字符是否唯一
      • 两整数之和
      • 只出现一次的数字II
      • 消失的两个数字
  • 鸽巢原理
  • 总结

本篇总结位运算中常见的算法题和思路,首先总结位运算中常见的题型

实现原理

基础位运算

位运算主要包含

  1. 左移 <<
  2. 右移 >>
  3. 按位取反 ~
  4. 按位与 &
  5. 按位或 |
  6. 按位异或 ^

位图思想

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

解法:(n>>x) & 1
原理:n右移x个单位,就令所求元素的二进制位移动到了第一位,再令其和1按位与,其他位都是0,只有第一位,如果n的这个位置为1,则结果为1,如果是0,则结果为0

2. 给定一个数n,将它的二进制表示的第x位改成1

解法:(1<<x) | n
原理:将1左移x个单位,就可以让二进制表示中1挪动到x的位置,再让这个左移后的1和n按位或,则就可以改变这个位置的0

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

解法:(~(1<<x)) & n
原理:将1左移x个单位,此时除了第x位置外,其余位置都为0,再令其按位取反,此时除了第x个位置外,其余地方都为1,再让这个数和n按位与,此时其余位置不变,第x的位置就会被改变为0

找最右侧数

1. 提取一个数n二进制中最右侧的1

解法:n & -n
原理:-n的原理是按位取反再+1,将最右侧的1,左边的区域全部取反就是-n

以下图例子为例:

在这里插入图片描述

2. 去掉一个数n二进制表示中最右侧的1

解法:n & (n-1)
原理:n-1就可以把最后一个1右侧的部分全部取反,此时按位与即可

按位异或

主要应用场景是单身狗等问题

算法思路

算法思路主要就是前面的这些原理,而大部分题目就是基于上面的原理进行一些叠加,只需要把题目进行一定程度的拆分,就可以解题了

典型例题

基础位运算

位运算在前面已经学过一些,这里主要总结一些比较常见的,比较有典型的例子,较简单的不归纳

只出现一次的数字

在这里插入图片描述

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

这里主要就是用到了按位异或的性质,按位异或的一个重要性质就是,如果一组数中每一个元素出现的此时都是偶数,只有一个是奇数,那么只需要把这个数组中所有的数据都按位异或起来,最终剩下的数就是那个数,这是由于按位异或自身的原理所产出的算法原理

只出现一次的数字III

在这里插入图片描述

class Solution 
{
public:
    vector<int> singleNumber(vector<int>& nums) 
    {
        int ret=0;
        for(auto ch :nums)
        {
            ret=ret^ch;
        }
        int lsb= ret==INT_MIN? ret:(ret&(-ret));
        int type1=0,type2=0;
        for(auto num:nums)
        {
            if(num &lsb)
            {
                type1 ^=num;
            }
            else
            {
                type2 ^=num;
            }
        }
        return {type1,type2};
    }
};

这个题本身就是基于上面题目的原理产生的,按位异或可以找到一组数中唯一出现的数,那么在这个题中却有两个数都唯一出现的,那么首先要做的就是进行分类,让这两个数归类到两个类中,以此能让其分开

那么分类的原理就是让所有数都按位异或,最终得到的就是这两个数按位异或的结果,那现在要做的就是要找到这两个数的不同点,然后把这两个数分开,具体方法就是用到了前面总结的找到不一样的1,令ret&(-ret),这样就可以找到二进制中最右侧的1,而这个1就是区分这两组数据的唯一标准

那下来做的就是把nums中的元素都和前面ret&(-ret)的结果按位异或,由于最右侧1的不同,就会天然的把数组里面的数据分成两组,而这两个不同的数据也会被分到两组中,这样找到了唯二的数据

经典题型

判断字符是否唯一

在这里插入图片描述

这里解决方法很多,可以用哈希表,排序,等等,这里采用是位图的思想,同时利用鸽巢原理进行一定程度的优化

class Solution 
{
public:
    bool isUnique(string astr) 
    {
        if(astr.size()>26)
        {
            return false;
        }

        int bitmap=0;
        for(auto ch : astr)
        {
            if((bitmap>>(ch-'a'))&1==1)
            {
                return false;
            }
            else
            {
                bitmap=bitmap | (1<<(ch-'a'));
            }
        }
        return true;
    }
};

两整数之和

在这里插入图片描述

此题需要用到按位与和按位异或的性质,按位与的性质除了相同为0,相异为1外,还有一个性质是无进位相加,因此可以利用这个性质解题,先用按位异或进行无进位相加,再求出进位是多少,再继续循环相加即可

而进位其实就是直接用的性质是两个数的二进制位都为1,则要进1,如果有一个为0则为0,其实这就是按位与的操作,但是由于进位要进1,因此这里把运算出的结果左移一个单位其实就是最终的结果,那么依据这个原理就可以求出最终的结果,当进位为0的时候循环结束

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

只出现一次的数字II

在这里插入图片描述

对于这个题首先可以采用哈希表的方法解决,但更好的方法是使用位运算,需要一定的观察

这里采用的是比特位计数的方法,原理就是通过观察这些数,找到每一个单独的比特位拥有的独特的规律,那对于这个题来说,规律就是对于数组nums,它当中每一个数的某一个比特位相加,最终相加的结果%3得到的就是这唯独一个数据的比特位的值,下图来解释

在这里插入图片描述

这里是举了具体的例子,如果把它抽象成字母来代表其中的数据,其实也是一样的,因为数字要不然是三个一组,要不然一个一组,而三个一组的数据最终都能被三整除,最后唯独不同的就是一个一组的数据

利用这个原理,就能很轻松的把原来的ret的每一个比特位都得到,得到每一个比特位最终这个数就是我们要求的数据

class Solution 
{
public:
    int singleNumber(vector<int>& nums) 
    {
        int ret=0;
        for(int i=0;i<32;i++)
        {
            int sum=0;
            for(auto ch:nums)
            {
                sum+=(ch>>i) & 1;
            }
            sum%=3;
            ret = ret | (sum<<i);
        }
        return ret;
    }
};

消失的两个数字

在这里插入图片描述

本题实现原理其实就是前面两个题的结合,分别是消失的数字只出现一次的数字III,但这个题的解法还有很多种,其中一种是借助鸽巢原理进行排序解决,也是一种思维较为巧妙的一种解法,可以借鉴学习

下面展示的是位运算的传统解法,鸽巢原理后续进行补充

class Solution 
{
public:
    vector<int> missingTwo(vector<int>& nums) 
    {
        int n=nums.size();
        // 找到两个数按位异或的结果
        int ret=0;
        for(int i=1;i<=n+2;i++)
        {
            ret ^= i;
        }
        for(auto ch : nums)
        {
            ret ^= ch;
        }
        // ret就是两个数按位异或的结果
        // 现在把这两个数分开找到即
        int lsb=ret&(-ret);    // 找到不同点
        int type1=0,type2=0;
        for(int i=1;i<=n+2;i++)
        {
            if(i & lsb)
            {
                type1 ^= i;
            }
            else
            {
                type2 ^= i;
            }
        }
        for(auto p : nums)
        {
            if(p & lsb)
            {
                type1 ^= p;
            }
            else
            {
                type2 ^= p;
            }
        }
        return {type1 , type2};
    }
};

鸽巢原理

鸽巢原理的概念就是,如果有n+1个鸽子飞进了n个鸽巢中,那么必定有鸽巢中至少飞进了2只鸽子

其实在前面的题目中,也有部分题可以使用鸽巢原理进行解决,例如在哈希表的使用中就经常可以用到鸽巢原理进行一定程度的优化,例如判断一个字符串中每个字符只出现一次,那么此时,如果字符串的长度大于26,那么说明这里必定会不是我们所要找的

类似的题目还有很多,但是对于上面的题目一个很简单的方法就是借助鸽巢原理进行排序来解决题目

依据这个原理,可以实现一个时间复杂度只有O(N)的排序,但是这个排序有一定的条件,条件就是要排序的数组必须是从1到n中所有数,并且每个数只出现一次,依据这个原理就可以解决问题

void sort(vector<int>& nums)
{  //6,1,2,5,-1,-1
	for (int i = 0; i < nums.size(); i++) 
	{
		while (nums[i] != -1 && nums[i] != i + 1)
		{
			swap(nums[i], nums[nums[i] - 1]);
		}
	}
}

int main()
{
	vector<int> v{ 6,1,2,5,-1,-1 };
	sort(v);
	return 0;
}

总结

位运算在面试的场景中有考察,也算是一种比较重要的算法,是应该多多练习的,而在练习的过程中要清楚位运算的基本解题原理,掌握了基本解题原理很多题目就是在基本的解题原理上进行的延伸,那么此时再进行解题就简单很多了

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

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

相关文章

边写代码边学习之TF Attention

1. 什么是Attention 注意力机制&#xff08;Attention Mechanism&#xff09;是机器学习和人工智能领域中的一个重要概念&#xff0c;用于模拟人类视觉或听觉等感知过程中的关注机制。注意力机制的目标是让模型能够在处理信息时&#xff0c;更加关注与任务相关的部分&#xff…

TDengine(2):wsl2+ubuntu20.04+TDengine安装

一、ubuntu系统下提供了三种安装TDengine的方式&#xff1a; 二、通过 apt 指令安装失败 因为是linux初学者&#xff0c;对apt 指令较为熟悉&#xff0c;因此首先使用了该方式进行安装。 wget -qO - http://repos.taosdata.com/tdengine.key | sudo apt-key add -echo "…

windows使用-设置windows的远程访问用户数量

文章目录 前言相关操作总结前言 作为IT工程师,使用服务器做相应的软件操作时常有的事。最近一段时间,我们的团队多个成员都需要远程登录到一台windows2003Server的服务器处理相应的业务。而默认情况下,Windows系统只允许一名用户远程到服务器上,这给小伙伴的工作造成一些不…

React-native环境配置与项目搭建

基础环境搭建 安装 node.js &#xff08;版本>12 ,推荐安装LTS稳定版本&#xff09; 安装 Yarn &#xff08;npm install -g yarn&#xff09; 安装 react native 脚手架 (npm install -g react-native-cli) windows 只能搭建Android 开发环境 Mac 下既能搭建Android 环境&…

斥资4亿,收购这家WLAN厂商,结果……

晚上好&#xff0c;我的网工朋友 不少朋友可能有隐形&#xff0c;2019年的时候&#xff0c;Juniper花费4.05亿美元&#xff0c;收购WiFi初创公司Mist Systems。 Mist Systems是一家买无线产品起家的公司&#xff0c;由前思科高管创建的。主打的产品是“AI-Driven WLAN”&…

linux安装firefox

1.下载对应包 https://www.mozilla.org/en-US/firefox/all/#product-desktop-release 2. 挂载桌面链接(如果/usr/bin/firefox下有的话,先删除) ln -s /opt/firefox/firefox /usr/bin/firefox 3.执行以下命令&#xff0c;即可启动Firefox客户端&#xff1a; firefox

TCP协议报文

前言 TCP/IP协议簇——打开虚拟世界大门中&#xff0c;已经给大家大致介绍了TCP/IP协议簇的分层。 TCP (Transmission Control Protocol)传输控制协议&#xff0c;在TCP/IP协议簇中&#xff0c;处于传输层。是为了在不可靠的互联网络&#xff08;IP协议&#xff09;中&#x…

LangChain学习笔记;给老师的ChatGPT使用指南;中国大模型顶级闭门会交流笔记;飞桨开源任务挑战大赛 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f916; 飞桨PaddlePaddle开源任务挑战大赛&#xff0c;首届「开放原子开源大赛」等你参与 官网&#xff1a;https://competition.atomgit.com…

redis未授权访问

文章目录 搭建环境漏洞复现安装Exlopit并使用 前提条件&#xff1a; 1.安装docker docker pull medicean/vulapps:j_joomla_22.安装docker-compose docker run -d -p 8000:80 medicean/vulapps:j_joomla_23.下载vulhub 搭建环境 输入下面命令&#xff0c;来到Redis的路径下&am…

基于Open3D的点云处理16-特征点匹配

点云配准 将点云数据统一到一个世界坐标系的过程称之为点云配准或者点云拼接。&#xff08;registration/align&#xff09; 点云配准的过程其实就是找到同名点对&#xff1b;即找到在点云中处在真实世界同一位置的点。 常见的点云配准算法: ICP、Color ICP、Trimed-ICP 算法…

深入探讨梯度下降:优化机器学习的关键步骤(一)

文章目录 &#x1f340;引言&#x1f340;什么是梯度下降&#xff1f;&#x1f340;损失函数&#x1f340;梯度(gradient)&#x1f340;梯度下降的工作原理&#x1f340;梯度下降的变种&#x1f340;随机梯度下降&#xff08;SGD&#xff09;&#x1f340;批量梯度下降&#xf…

添加YDNS免费的ipv6动态域名解析

背景 又到了一年一度的dns域名到期&#xff0c;寻找替代了&#xff0c;前几年用了阿里、华为的免费域名&#xff0c;支持了几个搭建在NAS上的微服务&#xff1b;一旦涉及到域名续费&#xff0c;价格就比首年上去了不少&#xff0c;所以&#xff0c;打算找个长期的免费域名。 搜…

在Windows 10上部署ChatGLM2-6B:掌握信息时代的智能对话

在Windows 10上部署ChatGLM2-6B&#xff1a;掌握信息时代的智能对话 硬件环境ChatGLM2-6B的量化模型最低GPU配置说明准备工作ChatGLM2-6B安装部署ChatGLM2-6B运行模式解决问题总结 随着当代科技的快速发展&#xff0c;我们进入了一个数字化时代&#xff0c;其中信息以前所未有的…

python数据分析基础—pandas中set_index()、reset_index()的使用

文章目录 一、索引是什么&#xff1f;二、set_index()三、reset_index() 一、索引是什么&#xff1f; 在进行数据分析时&#xff0c;通常我们要根据业务情况进行数据筛选&#xff0c;要求筛选特定情况的行或列&#xff0c;这时就要根据数据类型(Series或者DataFrame)的索引情况…

小苹果他爹V5.8版本最强小苹果影视盒子增加46条内置优质单仓线路

这款软件直接使用了俊版的小苹果接口&#xff0c;并且许多资源似乎都是直接调用的小苹果官方资源。这样一来&#xff0c;小苹果的作者可能会面临版权方面的问题&#xff0c;而且也让更多的用户对小苹果的收费模式产生质疑。在这个信息传播如此快速的时代&#xff0c;开发者们应…

816. 模糊坐标

816. 模糊坐标 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;参考代码&#xff1a;错误经验吸取 原题链接&#xff1a; 模糊坐标 完成情况&#xff1a; 解题思路&#xff1a; 参考代码&#xff1a; package 西湖算法题解___中等题;import java.util.Arra…

公司文件防泄密系统——「天锐绿盾透明加密系统」

「天锐绿盾透明加密系统」是一种公司文件防泄密系统&#xff0c;从源头上保障数据安全和使用安全。该系统采用文件过滤驱动实现透明加解密&#xff0c;对用户完全透明&#xff0c;不影响用户操作习惯。 PC访问地址&#xff1a; isite.baidu.com/site/wjz012xr/2eae091d-1b97-4…

贝叶斯神经网络 - 捕捉现实世界的不确定性

贝叶斯神经网络 - 捕捉现实世界的不确定性 Bayesian Neural Networks 生活本质上是不确定性和概率性的&#xff0c;贝叶斯神经网络 (BNN) 旨在捕获和量化这种不确定性 在许多现实世界的应用中&#xff0c;仅仅做出预测是不够的&#xff1b;您还想知道您对该预测的信心有多大。例…

ARM Cortex-M 的 SP

文章目录 1、栈2、栈操作3、Cortex-M中的栈4、MDK中的SP操作流程5、Micro-Lib的SP差别1. 使用 Micro-Lib2. 未使用 Micro-Lib 在嵌入式开发中&#xff0c;堆栈是一个很基础&#xff0c;同时也是非常重要的名词&#xff0c;堆栈可分为堆 (Heap) 和栈 (Stack) 。 栈(Stack): 一种…

2010-2021年上市公司和讯网社会责任评级CSR数据/和讯网上市公司社会责任数据

2010-2021年上市公司和讯网社会责任评级CSR数据 1、时间&#xff1a;2010-2021年 2、指标&#xff1a;股票名称、股票代码、年份、总得分、等级、股东责任、员工责任、供应商、客户和消费者权益责任、环境责任、社会责任、所属年份 3、样本量&#xff1a;4万 4、来源&#…