二进制中 1 的个数(C++ 和 Python 实现)
(说明:本博客中的题目、题目详细说明及参考代码均摘自 “何海涛《剑指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++ 实现
- /*
- * Author: klchang
- * Date: 2017.12.16
- * Description: Compute the number of 1 in the binary representation of an integer.
- */
- #include <iostream>
- #define INT_BITS 32
- // Generic method: bitwise and operation with a number that has only one 1 in binary.
- int numberOf_1_InBinary_Generic(int i)
- {
- int count = ;
- int shiftCount = ;
- while (i && shiftCount < INT_BITS)
- {
- if (i & ) {
- ++ count;
- }
- i = i >> ;
- ++ shiftCount;
- }
- return count;
- }
- // Fast method: bitwise and operation between integer i and (i-1).
- int numberOf_1_InBinary_Fast(int i)
- {
- int count = ;
- while (i)
- {
- std::cout << "iter " << count << ": " << i << std::endl;
- i = i & (i - );
- count ++;
- }
- return count;
- }
- void unitest()
- {
- int data[] = {-, , };
- std::cout << "---------------------- Generic Method -----------------------" << std::endl;
- for (int i = ; i < ; ++i)
- std::cout << "The number of 1 in the binary representation of " << data[i] << " is "
- << numberOf_1_InBinary_Generic(data[i]) << ".\n" << std::endl;
- std::cout << "----------------------- Fast Method --------------------------" << std::endl;
- for (int i = ; i < ; ++i)
- std::cout << "The number of 1 in the binary representation of " << data[i] << " is "
- << numberOf_1_InBinary_Fast(data[i]) << ".\n" << std::endl;
- }
- int main()
- {
- unitest();
- return ;
- }
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。
实现
- #!/usr/bin/python
- # -*- coding: utf8 -*-
- """
- # Author: klchang
- # Date: 2017.12.16
- # Description: Compute the number of 1 in the binary representation of an integer.
- """
- INT_BITS = 32
- MAX_INT = (1 << (INT_BITS - 1)) - 1 # Maximum Integer for INT_BITS
- # Generic method: bitwise and operation with a number that has only one 1 in binary.
- def number_of_1_in_binary_generic(num):
- count, bit = 0, 1
- while num and bit <= MAX_INT + 1:
- if bit & num:
- count += 1
- num -= bit
- bit = bit << 1
- return count
- # Fast method: bitwise and operation between integer num and (num-1).
- def number_of_1_in_binary_fast(num):
- count = 0
- while num:
- if num < - MAX_INT - 1 or num > MAX_INT:
- break
- print("iter %d: %d" % (count, num))
- count += 1
- num = num & (num-1)
- return count
- def unitest():
- nums = [-5, 0, 5]
- # Generic Method
- print("-" * 30 + " Generic Method " + "-" * 30)
- for n in nums:
- print("The number of 1 in the binary representation of %d is %d.\n" % (n, number_of_1_in_binary_generic(n)))
- # Fast Method
- print('\n' + "-" * 30 + " Fast Method " + "-" * 30)
- for n in nums:
- print("The number of 1 in the binary representation of %d is %d.\n" % (n, number_of_1_in_binary_fast(n)))
- if __name__ == '__main__':
- unitest()
参考代码
1. targetver.h
- #pragma once
- // The following macros define the minimum required platform. The minimum required platform
- // is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
- // your application. The macros work by enabling all features available on platform versions up to and
- // including the version specified.
- // Modify the following defines if you have to target a platform prior to the ones specified below.
- // Refer to MSDN for the latest info on corresponding values for different platforms.
- #ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
- #define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
- #endif
2. stdafx.h
- // stdafx.h : include file for standard system include files,
- // or project specific include files that are used frequently, but
- // are changed infrequently
- //
- #pragma once
- #include "targetver.h"
- #include <stdio.h>
- #include <tchar.h>
- // TODO: reference additional headers your program requires here
3. stdafx.cpp
- // stdafx.cpp : source file that includes just the standard includes
- // NumberOf1.pch will be the pre-compiled header
- // stdafx.obj will contain the pre-compiled type information
- #include "stdafx.h"
- // TODO: reference any additional headers you need in STDAFX.H
- // and not in this file
4. NumberOf1.cpp
- // NumberOf1.cpp : Defines the entry point for the console application.
- //
- // 《剑指Offer——名企面试官精讲典型编程题》代码
- // 著作权所有者:何海涛
- #include "stdafx.h"
- #include <string.h>
- #include <stdlib.h>
- // ====================方法一====================
- int NumberOf1(unsigned int n);
- int NumberOf1Between1AndN_Solution1(unsigned int n)
- {
- int number = ;
- for(unsigned int i = ; i <= n; ++ i)
- number += NumberOf1(i);
- return number;
- }
- int NumberOf1(unsigned int n)
- {
- int number = ;
- while(n)
- {
- if(n % == )
- number ++;
- n = n / ;
- }
- return number;
- }
- // ====================方法二====================
- int NumberOf1(const char* strN);
- int PowerBase10(unsigned int n);
- int NumberOf1Between1AndN_Solution2(int n)
- {
- if(n <= )
- return ;
- char strN[];
- sprintf(strN, "%d", n);
- return NumberOf1(strN);
- }
- int NumberOf1(const char* strN)
- {
- if(!strN || *strN < '' || *strN > '' || *strN == '\0')
- return ;
- int first = *strN - '';
- unsigned int length = static_cast<unsigned int>(strlen(strN));
- if(length == && first == )
- return ;
- if(length == && first > )
- return ;
- // 假设strN是"21345"
- // numFirstDigit是数字10000-19999的第一个位中1的数目
- int numFirstDigit = ;
- if(first > )
- numFirstDigit = PowerBase10(length - );
- else if(first == )
- numFirstDigit = atoi(strN + ) + ;
- // numOtherDigits是01346-21345除了第一位之外的数位中1的数目
- int numOtherDigits = first * (length - ) * PowerBase10(length - );
- // numRecursive是1-1345中1的数目
- int numRecursive = NumberOf1(strN + );
- return numFirstDigit + numOtherDigits + numRecursive;
- }
- int PowerBase10(unsigned int n)
- {
- int result = ;
- for(unsigned int i = ; i < n; ++ i)
- result *= ;
- return result;
- }
- // ====================测试代码====================
- void Test(char* testName, int n, int expected)
- {
- if(testName != NULL)
- printf("%s begins: \n", testName);
- if(NumberOf1Between1AndN_Solution1(n) == expected)
- printf("Solution1 passed.\n");
- else
- printf("Solution1 failed.\n");
- if(NumberOf1Between1AndN_Solution2(n) == expected)
- printf("Solution2 passed.\n");
- else
- printf("Solution2 failed.\n");
- printf("\n");
- }
- void Test()
- {
- Test("Test1", , );
- Test("Test2", , );
- Test("Test3", , );
- Test("Test4", , );
- Test("Test5", , );
- Test("Test6", , );
- Test("Test7", , );
- Test("Test8", , );
- }
- int _tmain(int argc, _TCHAR* argv[])
- {
- Test();
- return ;
- }
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 实现)的更多相关文章
- 【剑指offer】面试题 15. 二进制中 1 的个数
面试题 15. 二进制中 1 的个数 题目描述 题目:输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. Java 实现 方法一 public class Solution { // y ...
- 剑指offer 11:二进制中 1 的个数
题目描述 输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. 解题代码 法一: public class Solution { public int NumberOf1(int n) { ...
- 剑指offer——面试题15:二进制中 1的个数
// 面试题15:二进制中1的个数 // 题目:请实现一个函数,输入一个整数,输出该数二进制表示中1的个数.例如 // 把9表示成二进制是1001,有2位是1.因此如果输入9,该函数输出2. #inc ...
- 用js刷剑指offer(二进制中一的个数)
题目描述 输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. 牛客网链接 思路 如果一个整数不为0,那么这个整数至少有一位是1.如果我们把这个整数减1,那么原来处在整数最右边的1就会变为 ...
- 统计文件中单词的个数---Shell及python版
最近在看shell中有个题目为统计单词的个数,使用了awk功能,代码如下 #!/bin/bash ];then echo "Usage:basename $0 filename" ...
- 剑指Offer 二进制中一的个数
链接:https://www.nowcoder.com/questionTerminal/8ee967e43c2c4ec193b040ea7fbb10b8 来源:牛客网 public class So ...
- python 对列表中任意两个数进行操作 (python operate any two elements in list)
python中, 实现列表中的整型元素两两相乘或列表中的数组元素两两相与 1. 假设列表中的元素是整型, 可调用以下函数: def list_any_two_mul(mylist): num ...
- 剑指 offer set 5 二进制中 1 的个数
总结 1. 负数右移会保持其符号. 比如 0x80000000 右移, 其对应的绝对值也是 0X80000000, 其右移一位并保持符号, 得到 0XC0000000. 符号位保持, 使得负数永远都无 ...
- 转:对于一个字节(8bit)的变量,求其二进制表示中“1”的个数
转:http://toutiao.com/a4280977370/ [解法一] 可以举一个八位的二进制例子来进行分析.对于二进制操作,我们知道,除以一个 2,原来的数字将会减少一个0.如果除的过程中有 ...
随机推荐
- Python爬虫常用之登录(二) 浏览器模拟登录
浏览器模拟登录的主要技术点在于: 1.如何使用python的浏览器操作工具selenium 2.简单看一下网页,找到帐号密码对应的框框,要知道python开启的浏览器如何定位到这些 一.使用selen ...
- Oracle SQL Developer 查询时间格式
工具->首选项->数据库->NLS->日期格式: DD-MON-RR 修改为: YYYY-MM-DD HH24:MI:SS
- CentOS&.NET Core初试-3-Nginx的安装和配置
系列目录 CentOS的安装和网卡的配置 安装.NET Core SDK和发布网站 Nginx的安装和配置 安装守护服务(Supervisor) Nginx简介 Nginx是一个免费的,开源的,高 ...
- iview2.0 bug之+8 区的 DatePicker
请看以上细节图:工作案例小Demo 用心去做,不留遗憾!
- 深刻理解Python中的元类(metaclass)(转)
转载地址:http://blog.jobbole.com/21351/ 另外有几点理解记录下: 创建一个实例时,有时会传入参数,这些参数会同时传入 __init__() 和 __new__(),如: ...
- db2 tsm backup fails with rc–50(1)
2015-01-05-19.21.54.477532+000 E8484227A347 LEVEL: Error PID : 10027058 TID : ...
- HTML5开发手机项目-个人总结(转)
让网页的宽度自适应屏幕<meta name="viewport" content="width=device-width"/> 1)html上 ...
- 2014年北京网络赛 Instrusive HDU 5040 题解 优先队列
网赛的时候看了这道题,发现就是平常的那种基础搜索题. 由于加了一个特殊条件:可以一次消耗3秒或原地停留1秒. 那就不能使用简单的队列了,需要使用优先队列才行. 题意 告诉一副地图:一个起点,一个终点, ...
- Java的IO输入输出流类的介绍(有图)
一.字节流 1.InputStream/OutputStream(输入流与输出流几乎一一对应) 读取的方法 int read() int read(byte[] buffer) int r ...
- [LNMP]——LNMP环境配置
LNMP=Linux+Nginx+Mysql+PHP Install Nginx //安装依赖包 # yum install openssl openssl-devel zlib-devel //安装 ...