算法(5)——位运算

一、位运算概述

  • 程序中的所有数在计算机内存中都是以二进制的形式存储的

  • 位运算(Bitwise operation)就是直接对整数在内存中的二进制位进行操作,因此其执行效率非常高

  • 在程序一般使用位运算进行操作,会大大提高程序的性能

位运算的本质

  • 位运算是在二进制之间操作,粗略地说就是 0 和 1 之间的转换

位运算时会将数值转换为32位整型来进行运算,所以位运算遇到小数时,直接处理掉小数部分当成整数来运算,并且要是一个数的二进制表示超过32位,或者运算完后超过32位,那么就会出问题。所以不是所有的情况都适用位运算(可以利用位运算进行取整操作)

二、位运算操作符

位运算操作符有:

  • 按位非~

  • 按位与&

  • 按位或|

  • 按位异或^

  • 左移<<

  • 无符号右移>>>

  • 有符号右移>>

想必大家对这些操作符都很熟悉了,我在这里就不过多解释了

三、位运算相关操作

1、给一个数N,确定它的二进制表示中的第X位是0还是1?

(N>>X)&1

2、将一个数N的二进制第X位修改为1

N=N |(1<<X)

3、将一个数N的二进制第X位修改为0

N=N & (~(1<<X))

4、提取一个数(N)二进制表示中最右侧的1

N & -N

5、干掉一个数(N)二进制表示中最右侧的1

N & (N-1)

注意:我们在位运算时要关注位运算的优先级,我们最好都加括号(),这样就不会出错

四、位运算例题

4.1、判断字符串是否唯一

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

        题目描述:

        算法思路

利⽤「位图」的思想,每⼀个「⽐特位」代表⼀个「字符,⼀个 int 类型的变量的 32 位⾜够表⽰所有的⼩写字⺟。⽐特位⾥⾯如果是 0 ,表⽰这个字符没有出现过。⽐特位⾥⾯的值是 1 ,表⽰该字符出现过。

那么我们就可以⽤⼀个「整数」来充当「哈希表」。        代码实现1

class Solution {
public:
    bool isUnique(string astr) 
    {
        //位图
        int bitmap=0;
        for(auto e:astr)
        {
            int i=e-'a';
            if((bitmap>>i)&1)
            {
                return false;
            }   
            bitmap=bitmap|(1<<i);
        }
        return true;
    }
};

        代码实现2

哈希算法
class Solution {
public:
    bool isUnique(string astr) 
    {
        if(astr.size()>26)
        {
            return false;
        }
        unordered_map<char,int> arr;
        for(int i=0;i<astr.size();i++)
        {
            arr[astr[i]]++;
            if(arr[astr[i]]>1)
            {
                return false;
            }
        }
        return true;
    }
};

4.2、丢失的数字

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

        题目描述

        算法思路

设数组的⼤⼩为 n ,那么缺失之前的数就是 [0, n] ,数组中是在 [0, n] 中缺失⼀个数形成 的序列。

如果我们把数组中的所有数,以及 [0, n] 中的所有数全部「异或」在⼀起,那么根据「异或」 运算的「消消乐」规律,最终的异或结果应该就是缺失的数~

        代码实现

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

4.3、两整数之和

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

        算法思路

异或 ^ 运算本质是「⽆进位加法」;按位与 & 操作能够得到「进位」; 然后⼀直循环进⾏,直到「进位」变成 0 为⽌。        代码实现

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

4.4、只出现一次的数字Ⅱ

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

        题目描述

        算法思路

设要找的数位 ret 。由于整个数组中,需要找的元素只出现了「⼀次」,其余的数都出现的「三次」,因此我们可以根据所有数的「某⼀个⽐特位」的总和 %3 的结果,快速定位到 ret 的「⼀个⽐特位上」的值是0 还是 1

这样,我们通过 ret 的每⼀个⽐特位上的值,就可以将 ret 给还原出来。        代码实现        

class Solution {
public:
    int singleNumber(vector<int>& nums) 
    { 
        map<int,int> freq;
        for(auto e:nums)
        {
            freq[e]++;
        }
        int k=0;
        for(auto [first,second]:freq)
        {
            if(second==1)
            {
                k=first;
                break;
            }
        }
        return k;
    }
};

4.5、消失的两个数字

        题目描述

        算法思路:

本题就是 【丢失的数字】 + 【只出现一次的数字】 组合起来的题。

先将数组中的数和 [1, n + 2] 区间内的所有数「异或」在⼀起,问题就变成了:有两个数出现了「⼀次」,其余所有的数出现了「两次」。进⽽变成了  【只出现一次的数字】  这道题。

        代码实现

class Solution {
public:
    vector<int> missingTwo(vector<int>& nums) 
    {
        int sum=0;
        for(auto e:nums)
        {
            sum^=e;
        }
        for(int i=1;i<=nums.size()+2;i++)
        {
            sum^=i;
        }
        //此时sum就是我们要找的两个数字的异或
        int bitdex=0;
        for(int i=0;i<32;i++)
        {
            if((sum>>i&1)==1)
            {
                bitdex=i;
                break;
            }
        }
        int a=0,b=0;
        for(int i=1;i<=nums.size()+2;i++)
        {
            if(((1<<bitdex)&i))
            {
                a^=i;
            }
            else
            {
                b^=i;
            }
        }
        for(auto e:nums)
        {
            if((1<<bitdex)&e)
            {
                a^=e;
            }
            else
            {
                b^=e;
            }
        }
        return {a,b};
    }
};

版权声明:本文为博主作者:#欲速则不达#原创文章,版权归属原作者,如果侵权,请联系我们删除!

原文链接:https://blog.csdn.net/m0_69323023/article/details/136394766

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
乘风的头像乘风管理团队
上一篇 2024年4月1日
下一篇 2024年4月1日

相关推荐

此站出售,如需请站内私信或者邮箱!