zoukankan      html  css  js  c++  java
  • 二进制中1的个数

    • 算法-求二进制数中1的个数  
    • 问题描述  
    • 任意给定一个32位无符号整数n,求n的二进制表示中1的个数,比如n = 5(0101)时,返回2,n = 15(1111)时,返回4  
    •   
    • 这也是一道比较经典的题目了,相信不少人面试的时候可能遇到过这道题吧,下面介绍了几种方法来实现这道题,相信很多人可能见过下面的算法,但我相信很少有人见到本文中所有的算法。如果您上头上有更好的算法,或者本文没有提到的算法,请不要吝惜您的代码,分享的时候,也是学习和交流的时候。

    method1:
    将二进制数byte v mod 2得到该二进制数中的最末尾一位,若为1则计数加1,否则为0。将二进制数除以2得到新的二进制数,将其赋给v,循环操作。
    当得到的v中没有1即v==0时跳出循环。返回计数值即为二进制中1的个数。此算法时间复杂度为O(logv)。

    int count(int  v){
          int num=0;
       while(v){
        if(v%2==1){
                  num++;
        }
        v=v/2;
       }
       return num;
    }


    method2:
    由于采用位操作比余操作的效率高很多,故在此采用位操作。但是时间复杂度仍为O(logv)。
    将二进制数右移一位如10100010右移一位得到1010001,抛弃了最末尾一位。为了得到最末尾一位,将二进制数先与1进行与操作,若二进制数末尾为1,
    与1与操作后结果为1。否则结果为0。直接将得到的结果加到计数变量上即可(若结果为0,加0不影响计数。若结果为1,加1则计数+1)。然后再将原
    二进制数右移一位得到新的二进制数,直到新的二进制数为0,跳出循环。返回计数结果。

    int count1(int v){
          int num=0;
    
       while(v){
        num+=v&0x01;
        v=v>>1;
       }
       return num;
    }

    method3:
    为了简化这个问题,考虑只有一个1的情况。例如:01000000.
    要判断给定的二进制数中只有一个1,可以进行如下的操作:
    01000000 & (01000000-0x01)=01000000&00111111=0
    这样可以将该二进制中的1消除掉。再扩展到有多个1的情况。对于二进制数byte v:
    每进行一次v&=(v-1)将最低位的1变换成为0,计数器同时加1,直到v==0为止。
    该算法的时间复杂度为O(M),M为二进制中1的个数。

    int count2(int v){
         int num=0;
      while(v){
              v&=(v-1);
        num++;
      }
      return num;
    }

    method4:
    由于只有8位数据,于是可以直接将0-255的情况存储起来,并使用分支操作。
    该算法通过空间换时间来获取高的时间效率,最好情况下时间复杂度为O(1),最坏情况下时间复杂度为O(255),故解法不可取。

    int countTable[256]={
    0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,
    2,3,3,4,2,3,3,4,3,4,4,5,1,2,2,3,2,3,3,4,
    2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,
    4,5,5,6,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
    2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,
    3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,
    4,5,5,6,5,6,6,7,1,2,2,3,2,3,3,4,2,3,3,4,
    3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
    2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,
    4,5,5,6,4,5,5,6,5,6,6,7,2,3,3,4,3,4,4,5,
    3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,
    5,6,6,7,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
    4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
    };
    int count4(int v){
       return countTable[v];
    }

    扩展问题
    1. 如果变量是32位的DWORD,你会使用上述的哪一个算法,或者改进哪一个算法?
    2. 另一个相关的问题,给定两个正整数(二进制形式表示)A和B,问把A变为B需要改变
    多少位(bit)?也就是说,整数A 和B 的二进制表示中有多少位是不同的?

    将A和B进行异或操作,相同为0,不同为1,操作后的结果中1的个数即代表AB二进制表示中有多少位不同。
    设C=A^B,将问题转换为求C(二进制表示)中1的个数。采用method3即可求解。

    #include<iostream>
    #include "windows.h"
    
    using namespace std;
    
    int count5(int v){
         int num=0;
      while(v){
               v&=(v-1);
         num++;
      }
      return num;
    }
    int main(){
         int A,B;
      byte a,b,c;
      while(true){
              cin>>A>>B;
        c=A^B;
        int result=count5(c);
        cout<<"需要改变 "<<result<<" 位。"<<endl;
      }
      system("pause");
    }
  • 相关阅读:
    Elasticsearch常用插件集合(转)
    istio 安装与bookinfo示例运行(转)
    kubernetes发布tomcat服务,通过deployment,service布署(转)
    记一次ceph集群的严重故障 (转)
    Linux centos 7 安装NFS服务
    Centos7下使用Ceph-deploy快速部署Ceph分布式存储-操作记录(转)
    docker 安装 jmeter
    idea 2018.1破解激活方法,有效期至2099年
    MySQL和Oracle的区别
    SpringCloud面试题
  • 原文地址:https://www.cnblogs.com/yanglf/p/2714899.html
Copyright © 2011-2022 走看看