zoukankan      html  css  js  c++  java
  • 无符号整数翻转函数实现reverse_bits(unsigned int value)

    题目:

    Reverse Bits

    Reverse bits of a given 32 bits unsigned integer.

    For example, given input 43261596 (represented in binary as 00000010100101000001111010011100), return 964176192 (represented in binary as 00111001011110000010100101000000).

    Follow up:
    If this function is called many times, how would you optimize it?

    PS:leetcode

    一般的解决方案就是从左至右判断每一位,把获得的结果加在结果上,编码如下,

    class Solution {
    public:
        uint32_t reverseBits(uint32_t n) {
            uint32_t bit = 0;
            uint32_t result = 0;
            uint32_t tmp = n;
            while(bit<32)
            {
                if((tmp>>bit) & 1 == 1)
                    result = result + (1<<(31-bit));
        
                bit ++;
            }
        
            return result;
        }
    };

    这种方式简单易懂,但是效率不高,时间复杂度为O(n),n为数据类型的位数。

    咱们换个角度想想,既然我们给定的数可以通过移动获得每一位的数字,那么我们也可以移动结果来填充每一步的值。

    class Solution {
    public:
        uint32_t reverseBits(uint32_t n) {
            uint32_t  answer;
            uint32_t int i;
        
            answer = 0;
        
            /*把一个unsigned int 数字1一直左移,直到它变成全0的时候,也就得到了该机器内unsigned int的长度*/
            for (i = 1; i != 0; i <<= 1)
            {
                answer <<= 1;
                if (value & 1) { answer |= 1; }
                value >>= 1;
            }
        
            return answer;
        }
    };

    这种方案将结果按照数据类型的位数进行移动,每次移动时判断value的最后一位是否为1,如果为1,那么在结果的最后一位添加1,如果不是,继续移位。
    这种方案效率会高很多,因为我们知道对于C++编译器来讲,位操作肯定会比加法操作效率高得多。

    试想一下,我们还有没有更好的方案呢,答案当时是肯定的。

    http://graphics.stanford.edu/~seander/bithacks.html

    在斯坦福的这篇文章里面介绍了众多有关位操作的奇思妙想,有些方法的确让人称赞,其中对于位翻转有这样的一种方法,将数字的位按照整块整块的翻转,例如32位分成两块16位的数字,16位分成两个8位进行翻转,这样以此类推知道只有一位。

    对于一个8位数字abcdefgh来讲,处理的过程如下

    abcdefgh -> efghabcd -> ghefcdab -> hgfedcba

    class Solution {
    public:
        uint32_t reverseBits(uint32_t n) {
            n = (n >> 16) | (n << 16);
            n = ((n & 0xff00ff00) >> 8) | ((n & 0x00ff00ff) << 8);
            n = ((n & 0xf0f0f0f0) >> 4) | ((n & 0x0f0f0f0f) << 4);
            n = ((n & 0xcccccccc) >> 2) | ((n & 0x33333333) << 2);
            n = ((n & 0xaaaaaaaa) >> 1) | ((n & 0x55555555) << 1);
            return n;
        }
    };

    这种方法的效率为O(log sizeof(int))。

  • 相关阅读:
    二叉树的最大深度
    [CSP-S模拟测试]:飘雪圣域(莫队)
    [CSP-S模拟测试]:玩具(概率DP)
    [CSP-S模拟测试]:梦境(贪心+小根堆)
    [CSP-S模拟测试]:小P的生成树(数学+Kruskal)
    [CSP-S模拟测试]:小P的单调数列(树状数组+DP)
    [CSP-S模拟测试]:小P的2048(模拟)
    [CSP-S模拟测试]:简单的操作(二分图+图的直径)
    [CSP-S模拟测试]:简单的期望(DP)
    [CSP-S模拟测试]:简单的序列(DP)
  • 原文地址:https://www.cnblogs.com/lvxz/p/4332082.html
Copyright © 2011-2022 走看看