(说明:本博客中的题目题目详细说明参考代码均摘自 “何海涛《剑指Offer:名企面试官精讲典型编程题》2012年”)

题目

  请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如把 9 表示成二进制是 1001,有 2 位是 1。因此如果输入 9,该函数输出是 2。

算法设计思想

  计算一个整数的二进制表示中 1 的个数有多种算法。本文主要介绍两种算法,按位与运算算法和快速算法,更多算法,可以查看网友 zdd 的博文 “算法-求二进制数中1的个数”。

  按位与运算算法思想很简单,即对整数的二进制表示的每一位与 1 求与,所得结果为非 0 的个数,即为一个整数二进制表示中 1 的个数,这种算法所需的移位次数至少为整数的二进制表示中,数字 1 所在的最高位的位次(例如 0b0101,高位和低位所在的位次分别为 2 和 0),不够高效;

  快速算法,则不采用移位操作,而是用整数 i 与这个整数减 1 的值 i - 1,按位求与,如此可以消除,整数的二进制表示中,最低位的 1 。整数的二进制表示有几个 1,则只需计算几次。在 C/C++ 实现时,负整数溢出后为最大整数,但 Python 数值类型(Numeric Type)不会出现溢出的情况,所以,此时,还需要对边界值进行限定。

注,整数的二进制表示方式和移位操作处理方式:
1)整数的二进制表示方式:在计算机中,整数的二进制表示中,最高位为符号位。最高位为 0 时,表示正数; 最高位为 1 时表示负数。
2)对整数的移位操作:
当整数是负数时,右移时,最低位丢弃最高位补 1;  左移时,最高位丢弃,最低位补 0。
当整数是正数时,右移时,最低位丢弃,最高位补 0;  左移时,最高位丢弃,最低位补 0 。

C++ 实现

  1. /*
  2. * Author: klchang
  3. * Date: 2017.12.16
  4. * Description: Compute the number of 1 in the binary representation of an integer.
  5. */
  6.  
  7. #include <iostream>
  8.  
  9. #define INT_BITS 32
  10.  
  11. // Generic method: bitwise and operation with a number that has only one 1 in binary.
  12. int numberOf_1_InBinary_Generic(int i)
  13. {
  14. int count = ;
  15. int shiftCount = ;
  16.  
  17. while (i && shiftCount < INT_BITS)
  18. {
  19. if (i & ) {
  20. ++ count;
  21. }
  22. i = i >> ;
  23. ++ shiftCount;
  24. }
  25.  
  26. return count;
  27. }
  28.  
  29. // Fast method: bitwise and operation between integer i and (i-1).
  30. int numberOf_1_InBinary_Fast(int i)
  31. {
  32. int count = ;
  33. while (i)
  34. {
  35. std::cout << "iter " << count << ": " << i << std::endl;
  36. i = i & (i - );
  37. count ++;
  38. }
  39.  
  40. return count;
  41. }
  42.  
  43. void unitest()
  44. {
  45. int data[] = {-, , };
  46.  
  47. std::cout << "---------------------- Generic Method -----------------------" << std::endl;
  48. for (int i = ; i < ; ++i)
  49. std::cout << "The number of 1 in the binary representation of " << data[i] << " is "
  50. << numberOf_1_InBinary_Generic(data[i]) << ".\n" << std::endl;
  51.  
  52. std::cout << "----------------------- Fast Method --------------------------" << std::endl;
  53. for (int i = ; i < ; ++i)
  54. std::cout << "The number of 1 in the binary representation of " << data[i] << " is "
  55. << numberOf_1_InBinary_Fast(data[i]) << ".\n" << std::endl;
  56. }
  57.  
  58. int main()
  59. {
  60. unitest();
  61.  
  62. return ;
  63. }

Python 实现

原理

  为了更好的理解这个问题在 Python 中的实现,先简单介绍 Python 数值类型,需要注意 Python 2 和 Python 3 的数值类型是有些区别的。Python 2 的数值类型有 4 种类型,即 int, long, float 和 complex 。而在 Python 3 中,int 和 long 类型已经整合到一起,成为新的 int 类型,也就是说,Python 3 中,只有 3 种类型,即 int, float 和 complex。 对 bool 类型,在 Python 2 中,其是普通整型 int (at least 32 bits of precision)的子类型;在 Python 3 中,其是 int 类型(unlimited precision)的子类型。

  Python 2 的数值类型 int 是普通整型,是有范围的,可以通过 sys.maxint 获取其最大值,至少 32 bit。当 Python 2 程序中的整数值超出范围后,自动转换为 long 类型,而 long 类型是没有范围限制的,即 unlimited precision。在 Python 3 中,这两种类型被统一起来,表示为 int 类型,与 Python 2 的数值类型 long 相同,没有范围限定(unlimited precision)。也就是说,在 Python 中,整型数是没有溢出的(overflow)。在 Python 程序中,当对一个负整数与其减 1 后的值按位求与,若结果为 0 退出,循环执行此过程。由于整型数可以有无限的数值精度,其结果永远不会是 0,如此编程,在 Python 中,只会造成死循环。而在 C/C++ 中,整数(32 bit)的范围是 [ - 2147483648, 2147483647 ],与此相对, Python 2 中的 long 类型和 Python 3 中 int 类型,如果不指定整型数的位数,是没有范围限制的。

注:数值精度(numeric precision)是指数值中的数字位数(the number of digits);数值尺度(numeric scale)是指数值中的小数位数(the number of digits after the decimal point)。例如 123.45 可表示为 decimal(p = 5, s = 2),即 10进制,数值精度为 5, 数值尺度为 2。

实现

  1. #!/usr/bin/python
  2. # -*- coding: utf8 -*-
  3. """
  4. # Author: klchang
  5. # Date: 2017.12.16
  6. # Description: Compute the number of 1 in the binary representation of an integer.
  7. """
  8.  
  9. INT_BITS = 32
  10. MAX_INT = (1 << (INT_BITS - 1)) - 1 # Maximum Integer for INT_BITS
  11.  
  12. # Generic method: bitwise and operation with a number that has only one 1 in binary.
  13. def number_of_1_in_binary_generic(num):
  14.  
  15. count, bit = 0, 1
  16. while num and bit <= MAX_INT + 1:
  17. if bit & num:
  18. count += 1
  19. num -= bit
  20. bit = bit << 1
  21.  
  22. return count
  23.  
  24. # Fast method: bitwise and operation between integer num and (num-1).
  25. def number_of_1_in_binary_fast(num):
  26. count = 0
  27. while num:
  28. if num < - MAX_INT - 1 or num > MAX_INT:
  29. break
  30. print("iter %d: %d" % (count, num))
  31. count += 1
  32. num = num & (num-1)
  33.  
  34. return count
  35.  
  36. def unitest():
  37. nums = [-5, 0, 5]
  38. # Generic Method
  39. print("-" * 30 + " Generic Method " + "-" * 30)
  40. for n in nums:
  41. print("The number of 1 in the binary representation of %d is %d.\n" % (n, number_of_1_in_binary_generic(n)))
  42. # Fast Method
  43. print('\n' + "-" * 30 + " Fast Method " + "-" * 30)
  44. for n in nums:
  45. print("The number of 1 in the binary representation of %d is %d.\n" % (n, number_of_1_in_binary_fast(n)))
  46.  
  47. if __name__ == '__main__':
  48. unitest()

参考代码

1. targetver.h

  1. #pragma once
  2.  
  3. // The following macros define the minimum required platform. The minimum required platform
  4. // is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
  5. // your application. The macros work by enabling all features available on platform versions up to and
  6. // including the version specified.
  7.  
  8. // Modify the following defines if you have to target a platform prior to the ones specified below.
  9. // Refer to MSDN for the latest info on corresponding values for different platforms.
  10. #ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
  11. #define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
  12. #endif

2. stdafx.h

  1. // stdafx.h : include file for standard system include files,
  2. // or project specific include files that are used frequently, but
  3. // are changed infrequently
  4. //
  5.  
  6. #pragma once
  7.  
  8. #include "targetver.h"
  9.  
  10. #include <stdio.h>
  11. #include <tchar.h>
  12.  
  13. // TODO: reference additional headers your program requires here

3. stdafx.cpp

  1. // stdafx.cpp : source file that includes just the standard includes
  2. // NumberOf1.pch will be the pre-compiled header
  3. // stdafx.obj will contain the pre-compiled type information
  4.  
  5. #include "stdafx.h"
  6.  
  7. // TODO: reference any additional headers you need in STDAFX.H
  8. // and not in this file

4. NumberOf1.cpp

  1. // NumberOf1.cpp : Defines the entry point for the console application.
  2. //
  3.  
  4. // 《剑指Offer——名企面试官精讲典型编程题》代码
  5. // 著作权所有者:何海涛
  6.  
  7. #include "stdafx.h"
  8. #include <string.h>
  9. #include <stdlib.h>
  10.  
  11. // ====================方法一====================
  12. int NumberOf1(unsigned int n);
  13.  
  14. int NumberOf1Between1AndN_Solution1(unsigned int n)
  15. {
  16. int number = ;
  17.  
  18. for(unsigned int i = ; i <= n; ++ i)
  19. number += NumberOf1(i);
  20.  
  21. return number;
  22. }
  23.  
  24. int NumberOf1(unsigned int n)
  25. {
  26. int number = ;
  27. while(n)
  28. {
  29. if(n % == )
  30. number ++;
  31.  
  32. n = n / ;
  33. }
  34.  
  35. return number;
  36. }
  37.  
  38. // ====================方法二====================
  39. int NumberOf1(const char* strN);
  40. int PowerBase10(unsigned int n);
  41.  
  42. int NumberOf1Between1AndN_Solution2(int n)
  43. {
  44. if(n <= )
  45. return ;
  46.  
  47. char strN[];
  48. sprintf(strN, "%d", n);
  49.  
  50. return NumberOf1(strN);
  51. }
  52.  
  53. int NumberOf1(const char* strN)
  54. {
  55. if(!strN || *strN < '' || *strN > '' || *strN == '\0')
  56. return ;
  57.  
  58. int first = *strN - '';
  59. unsigned int length = static_cast<unsigned int>(strlen(strN));
  60.  
  61. if(length == && first == )
  62. return ;
  63.  
  64. if(length == && first > )
  65. return ;
  66.  
  67. // 假设strN是"21345"
  68. // numFirstDigit是数字10000-19999的第一个位中1的数目
  69. int numFirstDigit = ;
  70. if(first > )
  71. numFirstDigit = PowerBase10(length - );
  72. else if(first == )
  73. numFirstDigit = atoi(strN + ) + ;
  74.  
  75. // numOtherDigits是01346-21345除了第一位之外的数位中1的数目
  76. int numOtherDigits = first * (length - ) * PowerBase10(length - );
  77. // numRecursive是1-1345中1的数目
  78. int numRecursive = NumberOf1(strN + );
  79.  
  80. return numFirstDigit + numOtherDigits + numRecursive;
  81. }
  82.  
  83. int PowerBase10(unsigned int n)
  84. {
  85. int result = ;
  86. for(unsigned int i = ; i < n; ++ i)
  87. result *= ;
  88.  
  89. return result;
  90. }
  91.  
  92. // ====================测试代码====================
  93. void Test(char* testName, int n, int expected)
  94. {
  95. if(testName != NULL)
  96. printf("%s begins: \n", testName);
  97.  
  98. if(NumberOf1Between1AndN_Solution1(n) == expected)
  99. printf("Solution1 passed.\n");
  100. else
  101. printf("Solution1 failed.\n");
  102.  
  103. if(NumberOf1Between1AndN_Solution2(n) == expected)
  104. printf("Solution2 passed.\n");
  105. else
  106. printf("Solution2 failed.\n");
  107.  
  108. printf("\n");
  109. }
  110.  
  111. void Test()
  112. {
  113. Test("Test1", , );
  114. Test("Test2", , );
  115. Test("Test3", , );
  116. Test("Test4", , );
  117. Test("Test5", , );
  118. Test("Test6", , );
  119. Test("Test7", , );
  120. Test("Test8", , );
  121. }
  122.  
  123. int _tmain(int argc, _TCHAR* argv[])
  124. {
  125. Test();
  126.  
  127. return ;
  128. }

5. 参考代码下载

项目 10_NumberOf1 下载: 百度网盘

何海涛《剑指Offer:名企面试官精讲典型编程题》 所有参考代码下载:百度网盘

参考资料

[1]  何海涛. 剑指 Offer:名企面试官精讲典型编程题 [M]. 北京:电子工业出版社,2012. 77-82.

[2] Python Software Foundation. Python 2.7.14 Documentation, The Python Standard Library, 5.4. Numeric Types — int, float, long, complex [OL]. https://docs.python.org/2/library/stdtypes.html#numeric-types-int-float-long-complex. 2017.

[3] Python Software Foundation. Python 3.6.4rc1 Documentation, The Python Standard Library, 4.4. Numeric Types — int, float, complex [OL]. https://docs.python.org/3/library/stdtypes.html#numeric-types-int-float-complex. 2017.

[4] Stack Overflow Users. How do I interpret precision and scale of a number in a database [OL]. https://stackoverflow.com/questions/2377174/how-do-i-interpret-precision-and-scale-of-a-number-in-a-database.

二进制中 1 的个数(C++ 和 Python 实现)的更多相关文章

  1. 【剑指offer】面试题 15. 二进制中 1 的个数

    面试题 15. 二进制中 1 的个数 题目描述 题目:输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. Java 实现 方法一 public class Solution { // y ...

  2. 剑指offer 11:二进制中 1 的个数

    题目描述 输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. 解题代码 法一: public class Solution { public int NumberOf1(int n) { ...

  3. 剑指offer——面试题15:二进制中 1的个数

    // 面试题15:二进制中1的个数 // 题目:请实现一个函数,输入一个整数,输出该数二进制表示中1的个数.例如 // 把9表示成二进制是1001,有2位是1.因此如果输入9,该函数输出2. #inc ...

  4. 用js刷剑指offer(二进制中一的个数)

    题目描述 输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. 牛客网链接 思路 如果一个整数不为0,那么这个整数至少有一位是1.如果我们把这个整数减1,那么原来处在整数最右边的1就会变为 ...

  5. 统计文件中单词的个数---Shell及python版

    最近在看shell中有个题目为统计单词的个数,使用了awk功能,代码如下 #!/bin/bash ];then echo "Usage:basename $0 filename" ...

  6. 剑指Offer 二进制中一的个数

    链接:https://www.nowcoder.com/questionTerminal/8ee967e43c2c4ec193b040ea7fbb10b8 来源:牛客网 public class So ...

  7. python 对列表中任意两个数进行操作 (python operate any two elements in list)

    python中, 实现列表中的整型元素两两相乘或列表中的数组元素两两相与 1. 假设列表中的元素是整型, 可调用以下函数: def list_any_two_mul(mylist):      num ...

  8. 剑指 offer set 5 二进制中 1 的个数

    总结 1. 负数右移会保持其符号. 比如 0x80000000 右移, 其对应的绝对值也是 0X80000000, 其右移一位并保持符号, 得到 0XC0000000. 符号位保持, 使得负数永远都无 ...

  9. 转:对于一个字节(8bit)的变量,求其二进制表示中“1”的个数

    转:http://toutiao.com/a4280977370/ [解法一] 可以举一个八位的二进制例子来进行分析.对于二进制操作,我们知道,除以一个 2,原来的数字将会减少一个0.如果除的过程中有 ...

随机推荐

  1. Python爬虫常用之登录(二) 浏览器模拟登录

    浏览器模拟登录的主要技术点在于: 1.如何使用python的浏览器操作工具selenium 2.简单看一下网页,找到帐号密码对应的框框,要知道python开启的浏览器如何定位到这些 一.使用selen ...

  2. Oracle SQL Developer 查询时间格式

    工具->首选项->数据库->NLS->日期格式: DD-MON-RR 修改为: YYYY-MM-DD HH24:MI:SS

  3. CentOS&.NET Core初试-3-Nginx的安装和配置

    系列目录 CentOS的安装和网卡的配置 安装.NET Core SDK和发布网站 Nginx的安装和配置 安装守护服务(Supervisor) Nginx简介   Nginx是一个免费的,开源的,高 ...

  4. iview2.0 bug之+8 区的 DatePicker

    请看以上细节图:工作案例小Demo 用心去做,不留遗憾!

  5. 深刻理解Python中的元类(metaclass)(转)

    转载地址:http://blog.jobbole.com/21351/ 另外有几点理解记录下: 创建一个实例时,有时会传入参数,这些参数会同时传入 __init__() 和 __new__(),如: ...

  6. db2 tsm backup fails with rc–50(1)

    2015-01-05-19.21.54.477532+000 E8484227A347       LEVEL: Error PID     : 10027058             TID  : ...

  7. HTML5开发手机项目-个人总结(转)

    让网页的宽度自适应屏幕<meta name="viewport" content="width=device-width"/>    1)html上 ...

  8. 2014年北京网络赛 Instrusive HDU 5040 题解 优先队列

    网赛的时候看了这道题,发现就是平常的那种基础搜索题. 由于加了一个特殊条件:可以一次消耗3秒或原地停留1秒. 那就不能使用简单的队列了,需要使用优先队列才行. 题意 告诉一副地图:一个起点,一个终点, ...

  9. Java的IO输入输出流类的介绍(有图)

    一.字节流 1.InputStream/OutputStream(输入流与输出流几乎一一对应) 读取的方法   int read()   int read(byte[] buffer)   int r ...

  10. [LNMP]——LNMP环境配置

    LNMP=Linux+Nginx+Mysql+PHP Install Nginx //安装依赖包 # yum install openssl openssl-devel zlib-devel //安装 ...