(说明:本博客中的题目题目详细说明参考代码均摘自 “何海涛《剑指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. Java NIO原理和使用
  2. 网页中的超链接&lt;a&gt;标签
  3. 第七篇 SQL Server代理作业活动监视器
  4. [转]MVC自定义数据验证(两个时间的比较)
  5. mysql 统计 每天累计用户数
  6. insert 和 if x is not None
  7. JDBC操作封装
  8. Java中的Unsafe
  9. BOM之history对象
  10. Unity3d的序列帧动画
  11. java之重定向与转发
  12. java 集合框架(四)Set
  13. iOS 类方法 、野指针与空指针
  14. 在Ubuntu下编译Qt错误及处理办法
  15. 【原创】单片系统SoC
  16. HAProxy基础
  17. __getitem__函数
  18. Python 多进程编程之multiprocessing--Process
  19. 关于 Web Api 2 认证与授权
  20. 【Redis】Redis学习(五) Redis cluster模式详解

热门文章

  1. 项目版本不同导致Eclipse报错问题——关于在JDK1.7环境中,运行JDK1.8环境下编写的项目
  2. localStorage、sessionStorage用法总结
  3. WorldCount 结对项目
  4. java se系列(十一)线程
  5. centos7 装机配置及 mysql 安装过程
  6. java多线程-ReadWriteLock
  7. 生成随机32位Token43位asekey
  8. Git学习系列之集中式版本控制系统vs分布式版本控制系统
  9. 关于游标嵌套时@@FETCH_STATUS的值
  10. 收集整理mysql数据库设计规范与原则