【C++】位运算类题目总结

简介: 位运算类题目总结

一. 位运算符脑图


18f11c84297b468bbca98a3573f614d4.png

二. 相关题目

1. 统计二进制数中0的个数

解题思路:x &= (x-1);它的作用是每次循环把 x 的二进制中从右往左数的最后一位1变成0,直道变成全0为止,循环结束。


8d9bc90351c047319046c7253aaa7567.png

性能分析


时间复杂度:O(1),一般输入的数字都有固定的二进制位数。

空间复杂度:O(1),没有开辟额外的空间。

完整代码

size_t CountOne(int num)
{
    size_t count = 0;
    while(x)
    {
        ++count;
        // 通过这个迭代
        // 每次可以消除x二进制位中的一个1
        // 直到x最终为0
        x = x&(x-1);
    }
    return count;
}


2. 数组中只出现一次的数字

题目连接


解题思路


首先利用异或运算的规律:0异或任何数得到任何数,相同的数异或得0,用0去异或数组中的每一个元素,得到两个只出现一次的数字(我们假设是AB)异或在一起的结果。

这个结果的二进制中的1,表现的是A和B在这个比特位上的数字是不同的。我们就取从左往右第一个1所在的位数,假设是第3位,接着把原数组分成两组,分组标准是第3位是否为1。如此**,出现两次的数依然会被分到同一个组**,因为相同数字所有位都相同;而不同的数,肯定不在一组。然后把这两个组按照最开始的思路,拿数字0去依次异或,剩余的两个结果就是这两个只出现一次的数字。

性能分析


时间复杂度:O(n)。n为数组的长度。

空间复杂度:O(1)。

完整代码

class Solution 
{
public:
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) 
    {
        // 数组元素为0或输出型参数为空直接结束
        if(data.size() == 0 || num1 == nullptr || num2 == nullptr)
        {
            return;
        }
        // 1、算出两个只出现一次的数字异或在一起的结果
        int ret = 0;
        for(const auto e : data)
        {
            ret ^= e;
        }
        // 2、计算得到两个只出现一次的数字异或后最高比特位为1的位置
        int bit = 0;
        for(int i = 0; i < 32; ++i)
        {
            if((ret>>i) & 1)
            {
                bit = i;
            }
        }
        // 3、分成两组分别求出两个只出现一次的数字
        *num1 = 0;
        *num2 = 0;
        for(const auto e : data)
        {
            if(e & (1<<bit))
            {
                *num1 ^= e;
            }
            else 
            {
                *num2 ^= e;
            }
        }
    }
};


3. 数组中只出现一次的数字 II

题目连接


解题思路

首先如果我们不考虑这个只出现一次的数字,那么这个数组中的每一个数字都出现了三次。我们创建一个数组int count[32]去统计所有数的每一位比特位上一共有多少个1,统计结果 count 的每一个元素的值一定是 3n,如果把这个只出现一次的数字也给统计进去,那么 count 的每一个元素的值一定是3n 或 3n+1,根据 count 的每一个元素的值去模3,来还原出只那个出现一次的那个数字。


性能分析


时间复杂度:O(n)。n为数组的长度。

空间复杂度:O(1)。具体应该是数字的二进制位数,但一般输入的数字都有固定的二进制位数。

完整代码

class Solution {
public:
    int singleNumber(vector<int>& nums) 
    {
        // 1、统计所有数的每一位比特位上一共有多少个1
        // 要么3n要么3n+1
        vector<int> count(32);
        for(auto& e : nums)
        {
            for(int i=0; i<32; ++i)// 遍历每一个元素的每一位比特位
            {
                if(e & (1<<i))
                {
                    ++count[i];
                }
            }
        }
        // 2、根据count的结果还原出只出现一次的那个数字
        int ret=0;
        for(int i=0; i<32; ++i)
        {
            if(count[i]%3)
            {
                ret |= (1<<i);
            }
        }
        return ret;
    }
};


4. 不用加减乘除做加法

题目连接


解题思路


二进制位异或运算相当于对应位相加,不考虑进位

比如:

1 ^ 1 = 0 —> 1 + 1 = 0 (当前位值为0,进一位)

1 ^ 0 = 1 —> 1 + 0 = 1 (当前位值为1)

0 ^ 0 = 0 —> 0 + 0 = 0 (当前位值为0)


二进制位与运算相当于对应位相加之后的进位

比如:

1 & 1 = 1 —> 1 + 1 = 0 (当前位的值进一位)

1 & 0 = 0 —> 1 + 0 = 1 (当前位的值不进位)

0 & 0 = 0 —> 0 + 0 = 0 (当前位的值不进位)


两个数相加:对应二进制位相加的结果 + 进位的结果

比如:

3 + 2 --> 0011 + 0010 --> 0011 ^ 0010 + ((0011 & 0010) << 1)

—> (0011 ^ 0010) ^ ((0011 & 0010) << 1), 当进位之后的结果为0时,相加结束


完整代码


class Solution {
public:
    int add(int a, int b) 
    {
        // 进位数为0时,结束循环
        while(b)
        {
            // 得到二者和的无进位的结果
            int notCarry=a^b;
            // 得到进位数*10的结果
            b=((unsigned int)(a&b))*2;
            a=notCarry;
        }
        return a;
    }
};


相关文章
|
6天前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
28 5
|
12天前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
40 4
|
13天前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
37 4
|
1月前
|
存储 编译器 对象存储
【C++打怪之路Lv5】-- 类和对象(下)
【C++打怪之路Lv5】-- 类和对象(下)
27 4
|
1月前
|
编译器 C语言 C++
【C++打怪之路Lv4】-- 类和对象(中)
【C++打怪之路Lv4】-- 类和对象(中)
25 4
|
1月前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
22 1
|
1月前
|
存储 编译器 C语言
【C++打怪之路Lv3】-- 类和对象(上)
【C++打怪之路Lv3】-- 类和对象(上)
17 0
|
1月前
|
存储 编译器 C++
【C++类和对象(下)】——我与C++的不解之缘(五)
【C++类和对象(下)】——我与C++的不解之缘(五)
|
1月前
|
编译器 C++
【C++类和对象(中)】—— 我与C++的不解之缘(四)
【C++类和对象(中)】—— 我与C++的不解之缘(四)
|
1月前
|
C++
C++番外篇——对于继承中子类与父类对象同时定义其析构顺序的探究
C++番外篇——对于继承中子类与父类对象同时定义其析构顺序的探究
53 1