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

【Leetcode】[190] 颠倒二进制位

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

【Leetcode】[190] 颠倒二进制位

【Leetcode】[190] 颠倒二进制位

Author: Xin Pan

Date: 2022.3.13


题目

原题链接

颠倒给定的 32 位无符号整数的二进制位。

解法

考虑使用位运算来做,因为这32位0 1都很明显了。

示例 1:

输入:n = 00000010100101000001111010011100
输出:964176192 (00111001011110000010100101000000)
解释:输入的二进制串 00000010100101000001111010011100 表示无符号整数 43261596,
因此返回 964176192,其二进制表示形式为 00111001011110000010100101000000。

答案1 位移动+分治

怎么样,看到这个解法惊不惊喜意不意外。说真的,根本没想到分治。看了题解发现用了分治之后效果还是挺明显的。官方分治的题解是如下。

执行用时: 0 ms 内存消耗: 5.7 MB

class Solution
	{
	private:
		const uint32_t M1 = 0x55555555; // 01010101010101010101010101010101
		const uint32_t M2 = 0x33333333; // 00110011001100110011001100110011
		const uint32_t M4 = 0x0f0f0f0f; // 00001111000011110000111100001111
		const uint32_t M8 = 0x00ff00ff; // 00000000111111110000000011111111
	public:
		uint32_t reverseBits(uint32_t n)
		{
			n = n >> 1 & M1 | (n & M1) << 1; // 奇偶交换
			n = n >> 2 & M2 | (n & M2) << 2; // 每2位交换
			n = n >> 4 & M4 | (n & M4) << 4; // 每4位交换
			n = n >> 8 & M8 | (n & M8) << 8; // 每8位交换
			return n >> 16 | n << 16;
		}
	};

我用代码解释下其中的每行的含义。因为位的运算比较抽象,但是效率高。

#include 
#include 
using namespace std;

int main()
{
	uint32_t M1 = 0x55555555;
	uint32_t n = 43261596;

	// 运算符优先级 << >> 高于 按位与(&) 高于 按位异或(^) 高于 按位或(|)
	// 我自己记不住 按位与(&) 按位异或(^)  按位或(|) 三个运算什么时候结果是0,什么时候结果是1。为此我变了一个顺口溜
	// &:全1才是1;
	// |: 有1就是1;
	// ^: 不同才是1。
	// 记住顺口溜我们看下边的代码
	cout << "输入的二进制表示tt" << bitset(n) << endl;//int占4字节,一个字节8位,最终输出的是32个0或1
	cout << "输入>>1tttt" << bitset(n >> 1) << endl;//int占4字节,一个字节8位,最终输出的是32个0或1
	cout << "M1(奇偶掩膜)ttt" << bitset(M1) << endl;
	cout << "输入>>1&M1ttt" << bitset(n >> 1 & M1) << endl;
	cout << "输入&M1再<<1ttt" << bitset((n & M1) << 1) << endl;
	cout << "输入>>1&M1 | 输入&M1再<<1t" << bitset(n >> 1 & M1 | (n&M1) << 1) << endl << endl;


	cout << "输入的二进制表示tt" << bitset(n << 1) << endl;
	cout << "M1(奇偶掩膜)ttt" << bitset(M1) << endl;
	cout << "输入&M1tttt" << bitset(n & M1) << endl;
	cout << "输入&M1<<1ttt" << bitset((n & M1) << 1) << endl;
	cout << "输入<<1再&M1ttt" << bitset(n << 1 & M1) << endl;

	system("pause");
	return 0;
}

结果如下:

    &M1这个掩膜相当于固定提取当前奇数位置的值;

那么对于上半部分来说。首先将偶数位置移动到奇数位置,在和M1取按位与计算,就是将输入的偶数信息拿过来了。为什么右移一位不能说是奇数位到偶数位。因为第一位和最后一位会在移动(左移或者右移)过程中直接被抹掉。所以原值等于变了。故而我们不说奇数变到了偶数位置。

那么怎么将原先奇数位置转移到偶数位置呢,就是直接做按位与M1,再左移就可以了。现在我们有了各自移动好位置的奇数和偶数部分,下边就是将它们合并起来,那怎么做?直接做按位或就可以了。

这就完成了奇偶位数的互换工作了。因为采用分支算法,也就是将32位对半分,直到最小的维度相邻的两个值。

反过来我们计算了相邻(奇偶的互换),同理计算每2 4 8 16互换就完成任务了。

答案2 位移动

直接解法,一位位移动

执行用时: 4 ms 内存消耗: 5.9 MB

	class Solution
	{
	public:
		uint32_t reverseBits(uint32_t n)
		{
			uint32_t nret = 0;
			for (int i = 0; n > 0, i < 32; i++)
			{
				nret |= (n & 1) << (31 - i);
				n >>= 1;
			}
			return nret;
		}
	};
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/769469.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

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

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