问题
给定一个 32 位无符号整数n,要求把它的二进制位全部颠倒过来,并返回颠倒后的结果。
也就是说,原来在最低位的数字会变成最高位,原来在最高位的数字会变成最低位,中间的每一位也都要按顺序反过来。
示例 1:
输入:n = 00000010100101000001111010011100
输出:964176192
解释:颠倒后得到00111001011110000010100101000000,对应的十进制整数就是964176192。
示例 2:
输入:n = 11111111111111111111111111111101
输出:3221225471
解释:颠倒后得到10111111111111111111111111111111,对应的十进制整数就是3221225471。
思路
首先这道题最直观的想法很明显:既然要颠倒 32 个二进制位,那是不是可以把每一位都拿出来,然后按相反的顺序放到答案里。
题干说的是“颠倒二进制位”,那问题就变成了:怎么从n里依次拿到每一位?二进制里最低位是最容易拿到的,因为n & 1就能得到当前最低位是0还是1。
那拿到最低位之后,怎么让它出现在答案的正确位置?我们可以反过来想:答案res一开始是空的,每次先把res左移一位,给新的最低位腾出位置,然后把刚才从n中取出的这一位放进去。
拿一个简化的 4 位二进制举例,假设n = 1101:
第一次取出最低位 1,res = 1 第二次取出最低位 0,res = 10 第三次取出最低位 1,res = 101 第四次取出最低位 1,res = 1011不难发现,这个过程其实就是从右往左读取n,再从左往右构造res。因为题目固定是 32 位,所以循环 32 次就能保证每一位都被处理到,即使前面有很多个0也不会漏掉。
怎么在代码中维护这个过程?只需要两个变量:
res表示当前已经构造出的颠倒结果;n & 1表示当前要放进res的那一位。
每轮处理完当前最低位后,再让n右移一位,下一轮继续处理新的最低位即可。
解决
先定义答案变量
res。res一开始为0,表示还没有放入任何二进制位。接着循环 32 次。
因为题目要求的是 32 位整数,所以不能只循环到
n变成0为止。否则像前导0这类位置就不会被正确计算进去。每一轮先让
res左移一位。这样做相当于把已经放进去的位整体往高位移动,给当前新取出的位留出最低位位置。
res <<= 1再取出
n当前的最低位,放到res中。n & 1可以得到当前最低位,如果这一位是1,就通过或运算放入res;如果这一位是0,则res保持不变。res |= (n & 1)最后让
n右移一位。当前最低位已经处理完了,右移之后,下一位就会变成新的最低位。
注意:这里最好使用uint32_t这类无符号类型。因为如果使用int,当最高位为1时,右移可能会受到有符号数规则影响,而这道题本质上处理的是 32 位二进制本身。
classSolution{public:uint32_treverseBits(uint32_tn){uint32_tres=0;for(inti=0;i<32;++i){res<<=1;res|=(n&1);n>>=1;}returnres;}};时间复杂度为O(32),也就是常数级;空间复杂度为O(1)。