【优选算法之位运算】No.7--- 经典位运算算法


前言

在这里插入图片描述

👧个人主页:@小沈YO.
😚小编介绍:欢迎来到我的乱七八糟小星球🌝
📋专栏:优选算法
🔑本章内容:位运算
记得 评论📝 +点赞👍 +收藏😽 +关注💞哦~


一、位运算几种模型:

1.1 基础的位运算: << >> ~ & | ^

1.2 几种模型:

  • 给一个数n确定它的二进制表示中的第x位是0还是1 ===> (n>>x)&1
  • 将一个数n的二进制表示的第x位修改为1 ===> n|=(1<<x)
  • 将一个数n的二进制表示的第x位修改成0 ===> n&=(~(1<<x))
  • 位图思想 ===> 一个数字的二进制的每一位可以存储0或者1来表示模拟实现哈希
  • 提取一个数n的二进制表示中最右侧的1 ===> n&(~n) (-n《= =》 n取反+1)
  • 干掉一个数n的二进制表示中最右侧的1 ===> n&(n-1)
  • 异或运算的运算律 ===> (1) a ^ 0 = 0 (2) a ^ a = 0 (3) a ^ b ^ c = a ^ (b ^ c)

1.3 模型练习

二、位运算示例:

2.1 判定字符是否唯⼀

  1. 题⽬链接:⾯试题 01.01. 判定字符是否唯⼀
  2. 题⽬描述:
    在这里插入图片描述
  3. 解法(位图的思想):
    算法思路:
    利⽤「位图」的思想,每⼀个「⽐特位」代表⼀个「字符,⼀个 int 类型的变量的 32 位⾜够表⽰所有的⼩写字⺟。⽐特位⾥⾯如果是 0 ,表⽰这个字符没有出现过。⽐特位⾥⾯的值是 1 ,表⽰该字符出现过。那么我们就可以⽤⼀个「整数」来充当「哈希表」。
  4. C++代码
class Solution {
public:
    bool isUnique(string astr) 
    {
    	if(astr.size() > 26) return false;
        int ret=0;
        for(auto&e:astr)
        {
            if((ret>>(e-'a')&1)==1)return false;
            else
            ret|=(1<<(e-'a'));
        }
        return true;
    }
};

2.2 丢失的数字

  1. 题⽬链接:268. 丢失的数字

  2. 题⽬描述:
    在这里插入图片描述

  3. 解法(位运算):
    算法思路:
    设数组的⼤⼩为 n ,那么缺失之前的数就是 [0, n] ,数组中是在 [0, n] 中缺失⼀个数形成的序列。
    如果我们把数组中的所有数,以及 [0, n] 中的所有数全部「异或」在⼀起,那么根据「异或」运算的「消消乐」规律,最终的异或结果应该就是缺失的数~

  4. C++代码

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

2.3 两整数之和

  1. 题⽬链接:371. 两整数之和
  2. 题⽬描述:
    在这里插入图片描述
  3. 解法(位运算):
    算法思路:
    ◦ 异或 ^ 运算本质是「⽆进位加法」;
    ◦ 按位与 & 操作能够得到「进位」; 比如3&5 = = => 011&101= = =>001也就是同为1的时候相加会有进位但是这个进位要进给前一个位置所以还要右移1位
    ◦ 然后⼀直循环进⾏,直到「进位」变成 0 为⽌
  4. C++代码
class Solution {
public:
    int getSum(int a, int b) 
    {
        while(b)
        {
            int x=a^b;
            unsigned int y=(unsigned int)(a&b)<<1;
            a=x;
            b=y;
        }
        return a;
    }
};

2.4 只出现⼀次的数字 II

  1. 题⽬链接:137. 只出现⼀次的数字 II
  2. 题⽬描述:
    在这里插入图片描述
  3. 解法(⽐特位计数):
    算法思路:
    设要找的数位 ret 。
    由于整个数组中,需要找的元素只出现了「⼀次」,其余的数都出现的「三次」,因此我们可以根据所有数的「某⼀个⽐特位」的总和 %3 的结果,快速定位到 ret 的「⼀个⽐特位上」的值是 0 还是 1 。 这样,我们通过 ret 的每⼀个⽐特位上的值,就可以将 ret 给还原出来。
  4. C++代码
class Solution {
public:
    int singleNumber(vector<int>& nums) 
    {
        int ret=0;
        for(int i=0;i<32;i++)
        {
            int sum=0;
            for(auto&e:nums)
            {
                if((e>>i)&1==1)sum++;
            }
            sum%=3;
            if(sum==1)ret|=(1<<i);
        }
        return ret;
    }
};

2.5 消失的两个数字

  1. 题⽬链接:⾯试题 17.19. 消失的两个数字
  2. 题⽬描述:
    在这里插入图片描述
  3. 解法(位运算):
    算法思路:
    本题就是 268. 丢失的数字 + 260. 只出现⼀次的数字 III 组合起来的题。 先将数组中的数和 [1, n + 2] 区间内的所有数「异或」在⼀起,问题就变成了:有两个数出现了「⼀次」,其余所有的数出现了「两次」。进⽽变成了 260. 只出现⼀次的数字 III 这道题。
  4. C++代码
class Solution {
public:
    vector<int> missingTwo(vector<int>& nums) 
    {
        int n=nums.size()+2;
        int ret=0;
        for(int i=1;i<=n;i++)
            ret^=i;
        for(auto&e:nums)ret^=e;
        int l=0;
        for(int i=0;i<32;i++)
        {
            if(((ret>>i)&1)==1)
            {
                l=i;
                break;
            }
        }
        int a=0,b=0;
        for(auto&e:nums)
        {
            if(((e>>l)&1)==1)a^=e;
            else b^=e;
        }
        for(int i=1;i<=n;i++)
        {
            if(((i>>l)&1)==1)a^=i;
            else b^=i;
        }
        return {a,b};
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小沈YO.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值