【优选算法必刷100题:专题五】(位运算算法)第033~38题:判断字符是否唯一、丢失的数字、两整数之和、只出现一次的数字 II、消失的两个数字


🎬 个人主页艾莉丝努力练剑
专栏传送门 :《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录
Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享

⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平


🎬 艾莉丝的简介:


🎬艾莉丝的算法专栏简介:


文章目录

  • 常见位运算总结
    • [1 ~> 刷前必刷题单](#1 ~> 刷前必刷题单)
    • [2 ~> 博主手记](#2 ~> 博主手记)
  • [033 判断字符是否唯一](#033 判断字符是否唯一)
    • [​1.1 解法(位图的思想):](#1.1 解法(位图的思想):)
    • [1.2 算法实现](#1.2 算法实现)
    • [1.3 博主手记](#1.3 博主手记)
  • [034 丢失的数字](#034 丢失的数字)
    • [2.1 解法:位运算](#2.1 解法:位运算)
    • [2.2 算法实现](#2.2 算法实现)
    • [2.3 博主手记](#2.3 博主手记)
  • [035 两整数之和](#035 两整数之和)
    • [3.1 位运算解法的算法思路](#3.1 位运算解法的算法思路)
    • [3.2 算法实现](#3.2 算法实现)
    • [3.3 博主手记](#3.3 博主手记)
  • [036 只出现一次的数字 II](#036 只出现一次的数字 II)
    • [4.1 解法思路:比特位计数](#4.1 解法思路:比特位计数)
    • [4.2 算法实现](#4.2 算法实现)
    • [4.3 博主手记](#4.3 博主手记)
  • [037 消失的两个数字](#037 消失的两个数字)
    • [5.1 解法:位运算](#5.1 解法:位运算)
    • [5.2 算法实现](#5.2 算法实现)
    • [5.3 博主手记](#5.3 博主手记)
  • 结尾


常见位运算总结

1 ~> 刷前必刷题单

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

cpp 复制代码
class Solution {
public:
    int hammingWeight(int n) {
        int count = 0;
        while(n)
        {
            n &= (n - 1);
            count++;
        }
        return count;
    }
};
cpp 复制代码
// 奇偶性动态规划
// class Solution {
// public:
//     vector<int> countBits(int n) {
//         vector<int> ans(n + 1,0);
//         for(int i = 1;i < n + 1;i++)
//         {
//             ans[i] = ans[i >> 1] + (i & 1);
//         }
//         return ans;
//     }
// };

// 汉明重量问题解法
class Solution {
public:
    vector<int> countBits(int n) {
        vector<int> ans(n + 1);
        for(int i = 1;i < n + 1;i++)
        {
            int count = 0;
            int nums = i;
            while(nums)
            {
                nums &= (nums - 1);
                count++;
            }
            ans[i] = count;
        }
        return ans;
    }
};
cpp 复制代码
// 干掉一个数二进制位中表示最右侧的1
class Solution
{
public:
    int hammingDistance(int x,int y)
    {
        int val = x ^ y;
        int count = 0;
        while(val)
        {
            val &= (val - 1);
            count++;
        }
        return count;
    }
};

异或(^)运算的运算律相关的算法题:

cpp 复制代码
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int result = 0;
        int i = 0;
        while(i < nums.size())
        {
            result ^= nums[i];
            i++;
        }
        return result;
    }
};
cpp 复制代码
class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        vector<int> ans(2,0);
        int result = 0;
        int i = 0;
        while(i < nums.size())
        {
            result ^= nums[i];
            i++;
        }
        
        unsigned int val = result & (-(unsigned int)result);

        i = 0; // 重置i

        while(i < nums.size())
        {
            if(nums[i] & val)
            {
                ans[0] ^= nums[i];
            }
            else
            {
                ans[1] ^= nums[i];
            }
            i++;
        }

        return ans;
    }
};

2 ~> 博主手记


033 判断字符是否唯一

力扣链接: 面试题 01.01. 判定字符是否唯一

题目描述:

​1.1 解法(位图的思想):

利用「位图」的思想,每一个【比特位】代表一个【字符】,一个int类型的变量的32位足够表示所有的小写字母。比特位里面如果是0,表示这个字符没有出现过。比特位里面的值是1,表示该字符出现过。

那么我们就可以用一个【整数】来充当【哈希表】。

1.2 算法实现

cpp 复制代码
class Solution {
public:
    bool isUnique(string astr) {
        // 利用鸽巢原理做优化
        if(astr.size() > 26) return false;
        
        // 搞定位图
        int bitMap = 0;
        // 遍历字符串
        for(auto ch : astr)
        {
            int i = ch - 'a';
            // 先把重复的字符处理一下
            if((bitMap >> i) & 1 == 1)  return false;
            // 说明字符没有出现过,添加到位图中
            bitMap |= 1 << i;
        }
        return true;
    }
};

1.3 博主手记

本题整个的思路、算法原理、解题过程博主在纸上推导了一遍,大家可以参考一下手记的推导过程!最好做题的过程中自己也推导一遍!!!自己能够推导很重要!


034 丢失的数字

力扣链接: 268. 丢失的数字

题目描述:

2.1 解法:位运算

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

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

2.2 算法实现

cpp 复制代码
class Solution {
public:
    int missingNumber(vector<int>& nums) {
        // 用ret表示确实的那个数字
        int ret = 0;
        // 把数组中的数异或在一起
        for(auto x : nums) ret ^= x;
        // 把0~n中的数异或在一起
        for(int i = 0;i <= nums.size();i++)
            ret ^= i;

        return ret;
    }
};

2.3 博主手记

本题整个的思路、算法原理、解题过程博主在纸上推导了一遍,大家可以参考一下手记的推导过程!最好做题的过程中自己也推导一遍!!!自己能够推导很重要!


035 两整数之和

力扣链接: 371. 两整数之和

题目描述:

3.1 位运算解法的算法思路

  • 异或^运算本质是【无进位加法】;

  • 按位与&操作能够得到【进位】;

  • 然后一直循环进行,直到【进位】变成0为止。

3.2 算法实现

cpp 复制代码
class Solution {
public:
    int getSum(int a, int b) {
        while(b != 0)   // 一直重复这个操作
        {
            int x = a ^ b;    // 先算出无进位相加的结果
            unsigned int carry = (unsigned int)(a & b) << 1;   // 算出算出进位
            // 这里用unsigned int是考虑到a & b如果是-1的话,此时左移操作是没有定义的,用这种方式处理一下-1的情况(把-1当成无符号的整数)
            a = x;  // 把无进位相加结果给a
            b = carry;  // 把进位相加结果给b
        }
        return a;
    }
};

笔试场上可以不讲武德,面试官不看,而且代码也是会通过的:

cpp 复制代码
class Solution {
public:
    int getSum(int a, int b) {
        return a + b;
    }
};

3.3 博主手记

本题整个的思路、算法原理、解题过程博主在纸上推导了一遍,大家可以参考一下手记的推导过程!最好做题的过程中自己也推导一遍!!!自己能够推导很重要!


036 只出现一次的数字 II

力扣链接: 137. 只出现一次的数字 II

题目描述:

4.1 解法思路:比特位计数

设要找的数位ret

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

这样,我们通过ret的每一个比特位上的值,就可以将ret给还原出来。

4.2 算法实现

cpp 复制代码
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ret = 0;
        for(int i = 0;i < 32;i++)   // 依次去修改 ret 中的每一位
        {
            int sum = 0;
            for(int x : nums)   // 计算 nums 中所有的数的第 i 位的和
                if(((x >> i) & 1) == 1)
                sum++;

            sum %= 3;
            if(sum == 1) ret |= (1 << i);
        }
        return ret;
    }
};

4.3 博主手记

本题整个的思路、算法原理、解题过程博主在纸上推导了一遍,大家可以参考一下手记的推导过程!最好做题的过程中自己也推导一遍!!!自己能够推导很重要!


037 消失的两个数字

力扣链接: 面试题 17.19. 消失的两个数字

题目描述:

5.1 解法:位运算

本题就是268. 丢失的数字 + 260. 只出现一次的数字 III组合起来的题。

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

5.2 算法实现

cpp 复制代码
class Solution {
public:
    vector<int> missingTwo(vector<int>& nums) {
        // 1、将所有的数异或在一起
        int tmp = 0;
        for(auto x : nums) tmp ^= x;    // 异或原数组中的数
        // 异或1 ~ N
        for(int i = 1;i <= nums.size() + 2;i++) tmp ^= i;

        // 2、找出a,b中比特位不同的那一位
        int diff = 0;
        while(1)
        {
            if(((tmp >> diff) & 1) == 1)    break;
            else diff++;
        }

        // 3、根据diff位的不同,将所有的数划分为两类来异或
        int a = 0,b = 0;
        for(int x : nums)
            if(((x >> diff) & 1) == 1)  b ^= x;
            else a ^= x;
        for(int i = 1;i <= nums.size() + 2;i++)
            if(((i >> diff) & 1) == 1)  b ^= i;
            else a ^= i;

        return {a,b};
    }
};

5.3 博主手记

本题整个的思路、算法原理、解题过程博主在纸上推导了一遍,大家可以参考一下手记的推导过程!最好做题的过程中自己也推导一遍!!!自己能够推导很重要!


结尾

uu们,本文的内容到这里就全部结束了,艾莉丝再次感谢您的阅读!

结语:希望对学习算法相关内容的uu有所帮助,不要忘记给博主"一键四连"哦!

往期回顾

【优选算法必刷100题】第031~32题(前缀和算法):连续数组、矩阵区域和

🗡博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!🗡 ૮₍ ˶ ˊ ᴥ ˋ˶₎ა

相关推荐
花果山总钻风18 小时前
在 Debian 10.x 安装Chrome浏览器和ChromeDriver
运维·chrome·debian
光羽隹衡18 小时前
机器学习——DBSCAN算法
人工智能·算法·机器学习
vyuvyucd18 小时前
Java数组与Arrays类实战指南
数据结构·算法
csuzhucong18 小时前
七彩鹦鹉螺魔方
算法
逝川长叹18 小时前
利用 SSI-COV 算法自动识别线状结构在环境振动下的模态参数研究(Matlab代码实现)
前端·算法·支持向量机·matlab
山上三树18 小时前
详细介绍 C 语言中的匿名结构体
c语言·开发语言·算法
唐装鼠18 小时前
linux vscode解压版 AI账号无法登陆问题(浏览器无法打开vscode)
linux·运维·vscode
大猫和小黄18 小时前
Java开发过程中的各种ID生成策略
java·开发语言·id
EXtreme3518 小时前
【数据结构】彻底搞懂二叉树:四种遍历逻辑、经典OJ题与递归性能全解析
c语言·数据结构·算法·二叉树·递归