栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++刷题之旅(14)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++刷题之旅(14)

LeetCode算法入门(第十四天)

位运算 190.颠倒二进制位

解法:
方法一:每次把 res 左移,把 n的二进制末尾数字,拼接到结果 res 的末尾。然后把 n 右移。

class Solution {
public:
    uint32_t reverseBits(uint32_t n) {
        uint32_t res = 0;
        for(int i = 0; i < 32; ++i){
            res = (res << 1) | (n & 1);  //(n&1),n位与1,得n的最低位,再或res,既将n的最低为给res
            n >>= 1;   //n右移,
        }
        return res;

    }
};

方法二:分治法,把数字分为两半,然后交换这两半的顺序;然后把前后两个半段都再分成两半,交换内部顺序……直至最后交换顺序的时候,交换的数字只有 1 位。引用图片。

示例:  假设n二进制为:1011 0111 0011 1001 0011 1111 0110 1010
 n = (n >> 16) | (n << 16);   n >>> 16 就是左边16位被移动到了右侧, n << 16  就是右边16位被移动到了左侧,又 | 在了一起,所以,n变成了 0011 1111 0110 1010 1011 0111 0011 1001
 ((n & 0xff00ff00) >> 8);   左侧开始算0~7位,保留;8~15位,全变0;16~23位,保留;24~31位,全变0,n此时为0011 1111 0000 0000 1011 0111 0000 0000,然后统一右移8位,n为0000 0000 0011 1111 0000 0000 1011 0111
((n & 0x00ff00ff) << 8);   左侧开始算0~7位,全变0;8~15位,保留;16~23位,全变0;24~31位,保留此时n为0000 0000 0110 1010 0000 0000 0011 1001,然后左移8位,n为0110 1010 0000 0000 0011 1001 0000 0000
((n & 0xff00ff00) >>> 8) | ((n & 0x00ff00ff) << 8) 就是n的0~7位和8~15位交换了,16~23位和24~31位交换了,n为0110 1010 0011 1111 0011 1001 1011 0111
也就是说,整个过程是n的左16位,和右16位交换

n的左16位的内部,左8位和右8位交换;n的右16位的内部,左8位和右8位交换

接下来的一行,其实是,从左边开始算,0~7位内部,左4和右4交换;8~15位,左4和右4交换;...
((n & 0xf0f0f0f0) >> 4) n为 0000 0110 0000 0011 0000 0011 0000 1011
((n & 0x0f0f0f0f) << 4) n为 1010 0000 1111 0000 1001 0000 0111 0000
((n & 0xf0f0f0f0) >> 4) | ((n & 0x0f0f0f0f) << 4) n为 1010 0110 1111 0011 1001 0011 0111 1011
接下来的一行,其实是,从左边开始算,0~3位内部,左2和右2交换;4~7位,左2和右2交换;
最后的一行,其实是,从左边开始算,0~1位内部,左1和右1交换;2~3位,左1和右1交换;

在这里就顺便说一下常用的二进制数:

0xAAAAAAAA=10101010101010101010101010101010

0x55555555 = 1010101010101010101010101010101(奇数位为1,以1位为单位提取奇偶位)

 

0xCCCCCCCC = 11001100110011001100110011001100

0x33333333 = 00110011001100110011001100110011(以“2位”为单位提取奇偶位)

 

0xF0F0F0F0 = 11110000111100001111000011110000

0x0F0F0F0F = 1111000011110000111100001111(以“8位”为单位提取奇偶位)


0xFFFF0000 =11111111111111110000000000000000

0x0000FFFF = 1111111111111111(以“16位”为单位提取奇偶位)
 
class Solution {
public:
    uint32_t reverseBits(uint32_t n) {
        n = (n >> 16) | (n << 16);
        n = ((n & 0xff00ff00) >> 8) | ((n & 0x00ff00ff) << 8);  //n的0~7位和8~15位交换了,16~23位和24~31位交换了
        n = ((n & 0xf0f0f0f0) >> 4) | ((n & 0x0f0f0f0f) << 4);
        n = ((n & 0xcccccccc) >> 2) | ((n & 0x33333333) << 2);
        n = ((n & 0xaaaaaaaa) >> 1) | ((n & 0x55555555) << 1);
        return n;
    }
};

136.只出现一次的数字

解法:用set容器开辟了额外的空间,
根据题解思路,异或运算有如下三条性质:
1.任何数和0做异或运算,结果仍是原来的数;
2.任何数和其自身做异或运算,结果是0;
3.异或运算满足交换律和结合律。

class Solution {
public:
    int singleNumber(vector& nums) {
        unordered_set s;
        for(int i = 0; i < nums.size(); i++){
            if(s.find(nums[i]) == s.end()){    //如果set容器内不存在该数,则加入,否则删除
                s.insert(nums[i]);
            }
            else{
                s.erase(nums[i]);
            }
        }
        unordered_set::iterator it = s.begin();
        return *it;
    }
};

//由于交换律的存在,只存在一个只出现一次的值,故其他的值都可以通过异或自己本身得到0,然后0与唯一的那个数异或得到只出现一次的那个数。

class Solution {
public:
    int singleNumber(vector& nums) {
        // 异或
        int res = nums[0];
        for (int i = 1; i < nums.size(); i++) {
            res ^= nums[i];    //由于交换律的存在,只存在一个只出现一次的值,故其他的值都可以通过异或自己本身消除,得到唯一的值
        }
        return res;
    }
};


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/743987.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号