【LeetCode热题100】位运算

这篇博客先介绍了常见位运算操作,然后记录了关于位运算的几道题,包括判定字符是否唯一、丢失的数字、两整数之和、只出现一次的数字2、消失的两个数字。

在这一部分,我们不妨先来总结一下常见位运算操作:

1.基础位运算

>>是右移操作,<<是左移操作,~是按位取反,&是有0就是0,|是有1就是1,^有两种记忆方法1)相同为0,相异为1 2)无进位相加

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

我们约定,二进制的最右边为第0位,最左边为第31位,操作是(n>>x)&1,如果结果为0,那么第x位就是0,否则为1。

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

也就是第x位改为1,其它位保持不变,操作是 n |= (1<<x)。

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

操作是 n &= (~(1<<x)) 。

5.位图的思想

上面的2、3、4就是为位图来服务的,位图的本质是哈希表,让一个int的32个位的0/1来记录信息,利用2、3、4可以查看和修改位图。

6.提取一个数(n)二进制表示中最右侧的1(lowbit操作)

先来说结果,操作是 n&-n。我们需要先来看一下-n的本质:

-n的本质是将最右侧的1,左边的区域全部变成相反,此时相&后,左边区域全部变成0,右边区域本来就是0,所以&完之后只剩下最右侧的1。

7.干掉一个数(n)二进制表示中最右侧的1

先来说结果,操作是 n&(n-1) ,我们需要看一下n-1的本质:让最右侧及其右边全变成相反,左侧不变,这样相&之后,左侧不变,右侧全部变成0,这就把最右侧的1干掉了。

8.位运算的优先级

能加括号就加括号。

利用上面这几条,我们就可以解决LeetCode中的191、338、461这三道题了,

9.异或^运算的运算律

  1. a^a = 0(消消乐)

  2. a^0 = a

3)a^b^c = a^c^b

cpp 复制代码
class Solution {
public:
    bool isUnique(string astr) 
    {
        int bitmap = 0;
        for(auto e:astr)
        {
            int pos = e - 'a';
            if((bitmap>>pos) & 1) return false;
            bitmap |= (1<<pos);
        }
        return true;
    }
};

题目分析 :这道题有很多种解法,这里我们学习两种方法:哈希表和位图。第一种,使用哈希表,遍历整个字符串,将字符串中的每个字符依次放到哈希表中并判断条件,这种方法的时间复杂度和空间复杂度都是O(N)。第二种,使用位图,使用一个int位图,0位表示'a',1位表示'b',依次类推,因此只需要用到0~25位,遍历整个字符串,修改对应的bit,bit位为0表示之前没遇到这个字符,bit位为0表示之前遇到过这个字符。

此外,我们还可以使用鸽巢原理(抽屉原理)进行优化,如果字符长度大于26,说明肯定有重复字符,直接返回false。

cpp 复制代码
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;
    }
};

题目分析:这道题我们还是有很多思路的,包括哈希表、求和公式、异或运算。第一种,哈希表,将数组中所有数字依次放到哈希表中,然后看哈希表中缺失哪个数字。第二种,求和公式,计算出0~n之和,然后减去数组中的每个元素,剩下的就是缺失的元素。第三种,异或运算,将数组中每一个元素都异或到一起,然后再异或0~n中的每一个元素,结果就是缺失的数字。

cpp 复制代码
class Solution {
public:
    int getSum(int a, int b) 
    {
        while(b != 0)
        {
            int x = a^b;// x是无进位相加的结果
            int carry = (a&b)<<1;// carry 是进位
            a = x;
            b = carry;
        }
        return a;
    }
};

题目分析:这种直接用加法求和,大概率是用位运算操作,我们画图来看一下具体方法,主要想法是,a^b是无进位相加,a&b<<1可以表示进位,当进位为0时,循环结束。

cpp 复制代码
class Solution {
public:
    int singleNumber(vector<int>& nums) 
    {
        int i = 0;
        int sum = 0;
        int ret = 0;
        while(i <= 31)
        {
            //找到所有数第i位相加的结果
            for(auto e : nums)
            {
                sum += (e>>i)&1;
            }
            if(sum % 3 == 1) ret |= 1<<i;
            sum = 0;
            i++;
        }
        return ret;
    }
};

题目分析:我们将nums中每个元素的某一位全部加到一起,总共有4中情况:3n个0+0、3n个0+1、3n个1+0、3n个1+1。无论哪种情况,都将加和结果%3,最后得到的0、1、0、1就是所求结果的每一个比特位。

扩展:我们可以把这一道题扩展到除了某个元素只出现一次,其他出现n次,只需在将每一位求和后%n即可。

cpp 复制代码
class Solution {
public:
    vector<int> missingTwo(vector<int>& nums) 
    {
        int n = nums.size() + 2;
        int tmp = 0;
        //1.将所有数字异或到tmp上
        for(auto e : nums) tmp ^= e;
        for(int i = 1 ; i <= n ; i++) tmp ^= i;
        //2.找到a、b中的比特位的那一位
        int j = 0;
        for(j = 0 ; j < 32 ; j++)
        {
            if((tmp >> j) & 1) break;
        } 
        //3.按照tmp位分成两组
        int a = 0, b = 0;
        for(auto e : nums)
        {
            if((e >> j) & 1) a ^= e;
            else b ^= e;
        }
        //3.根据j位的不同,将所有的数划分为两类来异或
        for(int i = 1 ; i <= n ; i++)
        {
            if((i >> j) & 1) a ^= i;
            else b ^= i;
        }

        return {a,b};
    }
};

题目分析:这道题依然是用位运算的方式解决,第一步,先将nums中所有的数异或到同一个变量tmp上,然后再把1~N也异或到这个变量上,最后得到的就是缺失的两个数字的异或。第二步,找到tmp中,比特位为1的那一位。第三步,根据x位的不同,将nums中的数字划分成两组,将这两组分别异或到两个变量上,就可以得到缺失的两个数字。

相关推荐
专注仿真11 分钟前
问答大模型技术方案算法实现-RAPTOR树构建算法与BEG集成使用
python·算法
zlinear数据采集卡43 分钟前
数据采集卡从入门到精通(10):采样率与分辨率的核心关系——反比律、架构分布与过采样
arm开发·嵌入式硬件·算法·fpga开发·架构·开源
GeekZHR2 小时前
C语言指针进阶补充6:动态内存管理、mem系列内存函数、复杂指针声明,一次补齐指针的“三大盲区“
java·c语言·算法·指针
.道阻且长.2 小时前
8.LeetCode算法习题讲解--滑动窗口--长度最小的子数组
算法·leetcode·职场和发展
(❁´◡`❁)Jimmy(❁´◡`❁)2 小时前
P1156 [USACO01OPEN] 垃圾陷阱
算法·动态规划
疯狂打码的少年3 小时前
【数据结构】二叉排序树(BST)的定义与操作
数据结构·笔记·算法
lally.3 小时前
整数等差数列超图中的三个非微扰现象
算法
wabs6663 小时前
关于字符串【力扣541.反转字符串II的思考】
数据结构·算法·leetcode·字符串
土司大王3 小时前
LeetCode hot100——移动零
java·算法·leetcode
Tyler_TXZ4 小时前
C++C语言之——树
c语言·c++·算法·