C++算法(5)位运算

0.位运算基础

在看具体的题目之前,需要先了解一些常见的位运算操作。

(1)运算符

<<左移

>>右移

&按位与:有0则为0

|按位或:有1则为1

^按位异或:相同为0,相异为1

(2)具体操作

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

(n>>x)&1

x x x x x x x x->0 0 0 0 0 0 0 ?(若原位为0,则得到的数为0,若原位为1,则得到的数为1)

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

n|=(1<<x)

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

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

④位图的思想

用32位二进制数每一位中的0或1来表示信息

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

n&(-n)

意思是:

⑥将一个数n二进制表示中最右侧的1变成0

n&(n-1)

意思是:

⑦异或(^)运算的运算律

a^0=a

a^a=0

a^b^c=a^(b^c)

1.判定字符是否唯一

面试题 01.01. 判定字符是否唯一 - 力扣(LeetCode)

用位图的思想去做,每一位的1或0代表字符已经存在或否

但这其实也有局限性,一个int只有32个二进制位,这里的字符刚好只包括小写字母,如果是更多可能就不适用了。

进入循环先判断该字符在位图中的位置是0还是1,是1则表示已经存在过了,直接false,是0则存入。另外还有一个优化:根据鸽巢原理,原字符串长度如果超过26则一定有重复,可以提前判断一下。

代码如下:

cpp 复制代码
class Solution 
{
public:
    bool isUnique(string astr) 
    {
        if(astr.size()>26)
        {
            return false;
        }
        int bitMap=0;
        for(int i=0;i<astr.size();i++)
        {
            int n=astr[i]-'a';
            if(((bitMap>>n)&1)==0)
            {
                bitMap|=(1<<n);
            }
            else
            return false;
        }
        return true;
    }
};

2.丢失的数字

268. 丢失的数字 - 力扣(LeetCode)

方法有很多:

①用哈希表储存字符出现的次数

②高斯求和 Sn-sumnums

③位运算 创建一个不缺失的数组(不用真的创建,遍历的i就可以当作数组元素),和nums中的所有元素全部异或起来,得到的值就是缺失的数字

代码如下:

cpp 复制代码
class Solution {
public:
    int missingNumber(vector<int>& nums) 
    {
        int n=nums.size(),ret=0;
        for(int i=0;i<n;i++)
        {
            ret^=nums[i];
            ret^=i;
        }
        ret^=n;
        return ret;
    }
};

3.两整数之和

371. 两整数之和 - 力扣(LeetCode)

这种不允许用运算符的题可以考虑一下位运算

用异或解决(因为异或是无进位相加,只要找到进位即可)

只有1+1会产生进位,所以凡有0的进位都是0,用&

示例:13+28=41

代码如下:

cpp 复制代码
class Solution {
public:
    int getSum(int a, int b) 
    {
        int ret=0;
        unsigned int n=0;
        while(b)
        {
            ret=a^b;
            n=(unsigned int)(a&b)<<1;
            a=ret;
            b=n;
        }
        return a;
    }
};

4.只出现一次的数字Ⅱ

137. 只出现一次的数字 II - 力扣(LeetCode)

对于二进制表示的每一位,如果将数组所有元素相加起来,有且仅有4种情况:

可见,处理后的数位和要找的数的数位是一一对应的,所以可以循环遍历32个数位,将处理后的数填充到其中即可

代码如下:

cpp 复制代码
class Solution {
public:
    int singleNumber(vector<int>& nums) 
    {
        int ret=0;
        for(int i=0;i<32;i++)
        {
            int sum=0;
            for(auto x:nums)
            {
                if(((x>>i)&1))
                {
                    sum++;
                }
            }
            sum%=3;
            if(sum)
            {
                ret|=(1<<i);
            }
        }
        return ret;
    }
};

5.消失的两个数字

面试题 17.19. 消失的两个数字 - 力扣(LeetCode)

将不缺失的数组中的元素和题给数组中的元素异或在一起,最终得到的tmp是缺失的a和b异或的结果,由于异或相异为1,找到tmp的二进制表示中为1的位下标(其中一个),可知它是由该位上a和b的0和1异或而成的,根据该位为0或1,可以将其余所有元素分为两类,这两类分别异或可以分别得到a和b

代码如下:

cpp 复制代码
class Solution {
public:
    vector<int> missingTwo(vector<int>& nums) 
    {
        int tmp=0,b=0,a=0;
        int n=nums.size();
        for(int i=1;i<=n+2;i++)tmp^=i;
        for(auto x:nums) tmp^=x;
        int diff=0;
        for(;diff<32;diff++)
        {
            if(((tmp>>diff)&1)) break;
        }
        for(int i=1;i<=n+2;i++)
        {
            if(((i>>diff)&1)) a^=i;
            else b^=i;
        }
        for(auto x:nums)
        {
            if(((x>>diff)&1)) a^=x;
            else b^=x;
        }
        return{a,b};
    }
};
相关推荐
Chester_19994 小时前
CSP202203C.计算资源调度器
开发语言·数据结构·c++·蓝桥杯
裕晟资质规划6 小时前
武器装备科研生产单位保密资质申请方法论:条件模型与流程拆解
人工智能·算法
EXI-小洲6 小时前
Java 操作 Word:字符串替换、图片插入、动态生成表格与API接口下载
java·开发语言·spring boot·word
会周易的程序员6 小时前
给 PLC 写一个字节码虚拟机:STVM 虚拟机架构设计
开发语言·c++·虚拟机·软plc·iec61131·stvm
小灰灰搞电子6 小时前
完全驾驭 Qt 与数据库:C++ ORM 框架 QxOrm 原理与实践指南
数据库·c++·qt
QT界面美化性能优化6 小时前
QT+AI:使用AI技术为QT应用程序赋能
c++·人工智能·qt·opencv·qt教程·qt6.3
2601_961901707 小时前
SpringBoot使用Nacos进行application.yml配置管理
java·spring boot·spring
en.en..7 小时前
C语言 标准输入 / 输出缓冲区
算法
何以解忧,唯有..7 小时前
LangChain 工具调用(Tool Calling)实战指南
java·前端·langchain
QQ_21696290968 小时前
【源码编号:project79475】SpringBoot校内二手交易平台:商品发布、分类检索、留言交流、订单管理全流程实战
java·spring boot·后端