【优选算法必修篇——位运算】『面试题 01.01. 判定字符是否唯一&面试题 17.19. 消失的两个数字』

🎬 个人主页MSTcheng · CSDN
🌱 代码仓库MSTcheng · Gitee
🔥 精选专栏 : 《C语言
数据结构
《算法学习》
C++由浅入深

💬座右铭: 路虽远行则将至,事虽难做则必成!


前言:上一篇文章我们讲解了,前缀和算法,本篇文件我们就来讲解一下位运算!

文章目录

一、面试题 01.01. 判定字符是否唯一

1.1题目解析

这道题的要求很简单,就是判断一个字符串s中的所有字符是否全都不同,也就是s中的字符都只出现一次!这道题方法有很多种,我们只介绍位运算的方法。

1.2 算法原理


那具体如何实现将一个字符放入位图中检查某一个字母是否在位图中呢? 下面来看具体做法:

扩展:

1、给定一个数n,判断它的二进制表示中的第x位是0还是1?

其实就可以使用(N>>X) & 1来判断,如果结果是1那么该位就是1,如果是0那么该位就是0!

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

那么我们就可以用N |= (1<<X) 这样就可以把N二进制的第X位修改成1!

1.3代码编写

cpp 复制代码
class Solution {
public:
    bool isUnique(string astr) {
        //法二使用位图
        
        //鸽巢原理 超过26必有重复字符 
        if(astr.size()>26)
        {
            return false;
        }

        int biteMap=0;
        for(auto& ch:astr)
        {
            int i=ch-'a';//将字符减去'a'得到唯一的一个整数'a'-'a'=0
            //先判断字符是否已经出现过
            if(((biteMap>>i)&1)==1)
            {
                //说明之前已经存在该字符
                return false; 
            }
            //把当前字符加入到位图 将某个比特位设为1
            biteMap|=1<<i;
           
        }
        return true;

        
    }
};

二、268. 丢失的数字

2.1题目解析

题目的意思也非常简单就是从0到n里找到那个缺失的数,n位数组的大小。

2.2算法原理

异或运算的规律,比特位相同异或得0,比特位不同异或得1,即(相同为0,相异为1)。

2.3代码编写

cpp 复制代码
class Solution {
public:
    int missingNumber(vector<int>& nums) {
        
        int n=nums.size(); 
        int sum=n;
        //0-n(下标)的数与nums[i]的数异或
        for(int i=0;i<n;i++)
            sum^=i^nums[i];
        return sum;

    }
};

三、371. 两整数之和

3.1题目解析

题目的要求就是不使用加减法这两个运算符,完成两个数相加。

3.2算法原理

3.3代码编写

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

四、137. 只出现一次的数字 II

4.1题目解析

题目的要求很简单,就是找出一个数组中只出现一次的数字,其余的数均出现3次,只有一个数只出现一次,我们的任务就是找到这一个数。

4.2算法原理

这个方法其实特别巧妙,巧妙的运用了出现三个数对应的二进制位也一定出现3次,然后模上3就为0,而只出现一次的数的二进制位为1,模上3之后任然为1,从而将这各数筛选出来!!!

4.3代码编写

cpp 复制代码
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ret=0;
        for(int i=0;i<32;i++)//依次去修改ret中的每一位
        {
            int sum=0;//使用sum来统计nums中所以元素的第i位唯一的个数
            for(int x:nums)
            {
                if(((x>>i)&1)==1)
                {
                    sum++;
                }
            }
            sum=sum%3;//因为是出现3次所以模3 为0 出现一次的模3为1 所以可以找到出现一次的那个数
            if(sum==1)
            {
                ret=ret|(1<<i);
            }
        }
        return ret;
    }
};

五、面试题 17.19. 消失的两个数字

5.1题目解析

我直接来解释示例,输入1为什么返回2和3呢?

因为给定的vector的大小为1,而题目又告诉我们,数组中是缺少了两个数字的,所以原来的数组一定是输入数组的大小+2的!那么原数组就有3个数1,2,3(题目说了从1开始算)。而此时输入数组内部只有1,所以显然缺少了2和3。示例2同理。

5.2算法原理

5.3代码编写

c 复制代码
class Solution {
public:
    vector<int> missingTwo(vector<int>& nums) {
        int xorResult=0;//用于计算两个只出现一次的数字的异或结果

        for(int i=1;i<=nums.size()+2;i++)//小于等于要注意!
        {
            //先与1-n的数异或一遍
            xorResult^=i;
        }
        
        for(int num:nums)
        {
            //再与nums里的元素异或一遍
            xorResult^=num;
        }

        //此时就已经得到了那两个只出现一次的数字的异或结果!

        //定义一个mask找到这两个只出现一次的数字的异或结果的最低为1的比特位
        //用于区分这两个数

        int mask=xorResult&(-xorResult);

        //第三步、分组异或
        int num1=0,num2=0;
        for(int i=1;i<=nums.size()+2;i++)//小于等于要注意!
        {
            if((i&mask)!=0)
            {
                //将1到n中与mask 与运算为非0的数 分到一边
                num1^=i;
            }
            else
            {
                //将1到n中与mask 与运算为0的数 分到一边
                num2^=i;
            }
        }

        //然后再次拿着num1 和num2跟nums里的数进行与运算消去那些重复的数
        for(int num:nums)
        {
            if((num&mask)!=0)
            {
                //跟1到n中与mask 与运算为非0的那一组数 进行运算 
                num1^=num;
            }
            else
            {
                //跟1到n中与mask 与运算为0的那一组数 进行运算 
                num2^=num;
            }
        }
        return {num1,num2};
    }
};

六、总结

1、适用场景

海量整数去重、排序、判存 内存极度紧张,需极致压缩空间 数据范围已知且相对集中

2、常见坑

  1. 偏移 / 下标算错:bit 位置与数组下标换算错误
  2. 越界访问:数据超出预设最大范围
  3. 多数据冲突:不同数映射到同一位(未做哈希分离)
  4. 初始化不全:未清零导致脏数据误判
  5. 符号位问题:负数直接映射会出错
  6. 空间误判:范围极大时位图反而更占内存

常见的位操作的总结:

html 复制代码
MSTcheng 始终坚持用直观图解 + 实战代码,把复杂技术拆解得明明白白!
👁️ 【关注】 看普通程序员如何用实用派思路搞定复杂需求
👍 【点赞】 给 "不搞虚的" 技术分享多份认可
🔖 【收藏】 把这些 "好用又好懂" 的干货技巧存进你的知识库
💬 【评论】 来唠唠 ------ 你踩过最 "离谱" 的技术坑是啥?
🔄 【转发】把实用技术干货分享给身边有需要的程序员伙伴
技术从无唯一解,让我们一起用最接地气的方式,写出最扎实的代码! 🚀💻

感谢能够看到这里的小伙伴,如果这篇文章有帮到您,还请给个三连!你们的持续支持是我更新最大的动力!谢谢!

相关推荐
weixin_421922692 小时前
模板元编程性能分析
开发语言·c++·算法
蹦哒2 小时前
Kotlin 与 Java 语法差异
java·python·kotlin
2401_851272992 小时前
C++中的类型擦除技术
开发语言·c++·算法
左左右右左右摇晃2 小时前
Java并发——并发编程底层原理
java·开发语言
Liu628882 小时前
C++命名空间使用规范
开发语言·c++·算法
tankeven2 小时前
【无标题】
数据结构·c++·算法
bbbb3652 小时前
算法性能建模的数值方法与误差分析的技术7
算法
2501_945424802 小时前
模板代码模块化设计
开发语言·c++·算法
一个有温度的技术博主2 小时前
Redis系列八:Jedis连接池在java中的使用
java·redis·bootstrap