【小白笔记】将十进制数(Decimal)转换为二进制数(Binary),并计算二进制表示中“1”的个数
使用Python实现一个函数,用于将十进制数(Decimal)转换为二进制数(Binary),并计算二进制表示中“1”的个数。
Python 实现
这里提供三种不同的 Python 实现方法:
方法一:使用 Python 内置函数 bin() 和 count() (最简洁)
Python 的内置函数 bin() 可以直接将整数转换为以 '0b' 开头的二进制字符串,然后使用字符串的 count() 方法计算 ‘1’ 的数量。
def count_ones_in_binary_builtin(decimal_num):"""使用 Python 内置函数 bin() 和 count() 计算十进制数转换为二进制后 1 的个数。Args:decimal_num (int): 要转换的十进制非负整数。Returns:int: 二进制表示中 1 的个数。"""if decimal_num < 0:# 通常计算非负整数,如果需要处理负数,则需要考虑补码表示# 这里仅处理非负整数,可以根据实际需求调整return "输入必须是非负整数"# 1. 使用 bin() 转换为二进制字符串,例如 13 -> '0b1101'binary_string = bin(decimal_num)# 2. 使用 count('1') 计算 '1' 的个数ones_count = binary_string.count('1')# 打印转换过程(可选)print(f"十进制数 {decimal_num} 转换为二进制是: {binary_string[2:]}")return ones_count# 示例
number = 13 # 二进制为 1101,有 3 个 1
count1 = count_ones_in_binary_builtin(number)
print(f"二进制中 1 的个数为: {count1}\n")number = 25 # 二进制为 11001,有 3 个 1
count2 = count_ones_in_binary_builtin(number)
print(f"二进制中 1 的个数为: {count2}")
方法二:使用位运算 (Bitwise Operation) (最快且推荐)
这是计算机科学中常用的方法,尤其是 Brian Kernighan’s Algorithm(布赖恩·科尼干算法)。它通过不断地进行 n = n & (n - 1) 操作来消除数字 nnn 最右边的 ‘1’,直到 nnn 变为 0。循环的次数即为 ‘1’ 的个数。
- 位运算 (Bitwise Operation):
- 解释:直接对数字在内存中的二进制位进行操作的运算,比如“与”(AND,
&)、“或”(OR,|)、“非”(NOT,~)和“异或”(XOR,^)。 - 词源来历:由 Bit(位,即二进制数字 0 或 1)和 Operation(操作)组成。
- 解释:直接对数字在内存中的二进制位进行操作的运算,比如“与”(AND,
def count_ones_in_binary_bitwise(decimal_num):"""使用位运算(Brian Kernighan 算法)计算十进制数转换为二进制后 1 的个数。Args:decimal_num (int): 要转换的十进制非负整数。Returns:int: 二进制表示中 1 的个数。"""if decimal_num < 0:return "输入必须是非负整数"count = 0n = decimal_num# 当 n 不为 0 时循环while n > 0:# n & (n - 1) 的作用是消除 n 最右边的一个 '1'n = n & (n - 1)count += 1return count# 示例
number = 13 # 1101
count1 = count_ones_in_binary_bitwise(number)
print(f"使用位运算计算:十进制数 {number} 的二进制中 1 的个数为: {count1}\n")number = 31 # 11111
count2 = count_ones_in_binary_bitwise(number)
print(f"使用位运算计算:十进制数 {number} 的二进制中 1 的个数为: {count2}")
方法三:传统除法取余法 (Modulo and Division) (最基础)
这是手动进行十进制转二进制运算的模拟:不断将数字除以 2 并取余数(即二进制位),直到商为 0。
- 取模 (Modulo):
- 解释:数学和计算机科学中的运算,计算一个数被另一个数除后的余数。
- 词源来历:英文 Modulo 源自拉丁语 modulus,意为“小测量,小尺度”,常指代这种求余数的运算。
def count_ones_in_binary_traditional(decimal_num):"""使用传统的除法取余法计算十进制数转换为二进制后 1 的个数。Args:decimal_num (int): 要转换的十进制非负整数。Returns:int: 二进制表示中 1 的个数。"""if decimal_num < 0:return "输入必须是非负整数"if decimal_num == 0:return 0count = 0n = decimal_numwhile n > 0:# 取余数:n % 2,如果余数是 1,则计数器加 1if n % 2 == 1:count += 1# 整数除法:n // 2,相当于向右移位n = n // 2return count# 示例
number = 13
count1 = count_ones_in_binary_traditional(number)
print(f"使用传统方法计算:十进制数 {number} 的二进制中 1 的个数为: {count1}\n")number = 10 # 1010
count2 = count_ones_in_binary_traditional(number)
print(f"使用传统方法计算:十进制数 {number} 的二进制中 1 的个数为: {count2}")
1. Python 内置函数 bin() 和 count() 的记忆方法
| 函数 | 功能 | 记忆联想 (Memory Association) |
|---|---|---|
bin() | 将整数转换为以 '0b' 开头的二进制字符串。 | Binary 的前三个字母。想到 Binarization(二值化),即转换为二进制。 |
count() | 统计一个字符串或列表中特定元素的出现次数。 | Count 就是“计数”的意思,非常好记。无论是在字符串(统计字符)还是列表(统计元素)中,它都用于统计数量。 |
记忆技巧:结合应用场景
将这两个函数放在一起记忆,因为它们在“数 111 的个数”这个场景下是完美组合:
- 第一步(转换):我需要把数字变成二进制,所以用
bin()。 - 第二步(计数):我需要数里面的 111,所以用字符串的
count('1')方法。
Python 内置函数 (Built-in Functions)
- 解释:Python 语言自带的、可以直接使用的函数,无需导入任何模块。
- 如何记忆:Python 的内置函数数量有限且常用,建议通过多查文档、多写代码的方式逐步熟悉。常见的如
print()、len()、type()、input()、int()等,都是必掌握的。当您遇到一个需求时,先思考“Python 有没有内置的功能可以实现?”,这会促使您去查找和记忆。
2. print(f"...") 的详细含义、与 return 的区别以及常见语法
A. print(f"十进制数 {decimal_num} 转换为二进制是: {binary_string[2:]}")
| 部分 | 含义 | 解释 |
|---|---|---|
print() | 函数名 | 作用是将内容输出到标准输出设备(通常是控制台/屏幕)。 |
f"..." | F-String | 叫做 Formatted String Literal(格式化字符串字面量),是 Python 3.6 引入的简洁字符串格式化方法。 |
{} | 占位符 | 在 F-String 中,花括号 {} 内可以直接放入 Python 表达式或变量,程序运行时会用它们的值替换 {}。 |
decimal_num | 变量 | 打印变量 decimal_num 的值。 |
binary_string[2:] | 切片 (Slice) | 对字符串 binary_string 进行切片操作。bin() 函数的结果是 '0b1101',[2:] 的意思是从索引 2 开始取到字符串末尾,目的是去掉前缀 '0b',只保留纯二进制字符串。 |
B. print 与 return 的根本区别
| 特性 | print() | return |
|---|---|---|
| 作用 | 输出:将数据显示给用户(在控制台/屏幕上)。 | 返回:将一个值从函数内部传递给函数被调用的地方(调用者)。 |
| 中断 | 不会中断函数的执行。 | 会立即中断函数的执行,并将结果带回。 |
| 必须性 | 可选。函数可以没有 print。 | 可选。如果函数不需要返回值,可以省略 return,此时函数默认返回 None。 |
记忆方法:
- Print:像按下了打印机,把内容印在屏幕上。
- Return:像一个快递员,带着结果返回到您调用它的地方。
C. 常见 print 语法(字符串格式化)
| 方法 | 语法 | 优势/特点 |
|---|---|---|
| F-String (推荐) | print(f"Name: {name}, Age: {age}") | 最简洁、可读性高,直接在字符串内嵌入表达式。 |
.format() | print("Name: {}, Age: {}".format(name, age)) | 兼容性好(Python 2.7+),将值按顺序或通过关键字/索引代入。 |
% 占位符 (旧) | print("Name: %s, Age: %d" % (name, age)) | 类似 C 语言,但不够灵活,不推荐在新代码中使用。 |
D. "".join() 的用法
这是字符串操作中一个非常常用且高效的用法,通常用于将列表(List)或元组(Tuple)中的字符串元素连接成一个单一的字符串。
- 语法:
分隔符字符串.join(可迭代对象) - 工作原理:它用前面的分隔符字符串,将可迭代对象(如列表)中的所有元素连接起来。
| 示例 | 结果 | 解释 |
|---|---|---|
", ".join(["A", "B", "C"]) | "A, B, C" | 使用逗号和空格 ", " 连接。 |
"".join(["h", "e", "l", "l", "o"]) | "hello" | 使用空字符串 "" 连接,即紧密拼接。 |
记忆方法:把 "".join() 想象成一条拉链,"" 是拉链把手,它负责将拉链两边的元素(列表中的字符串)连接 (join) 起来。
3. 位运算、入门与学习建议
A. 位运算 (Bitwise Operation)
- 解释:位运算是直接对数字在计算机内部的二进制位(Bit,即 000 或 111)进行操作的运算。它比普通的加减乘除运算更快,因为它是硬件级别的操作。
- 常用:在需要极致性能(如嵌入式开发、图形学)、加密算法、以及高效处理整数(如您遇到的数 111 的个数)时,位运算非常常用且高效。
| 运算符 | 英文名称 | 符号 | 作用 |
|---|---|---|---|
| 按位与 | AND | & | 两位都为 111 时结果为 111,否则为 000。 |
| 按位或 | OR | ` | ` |
| 按位异或 | XOR | ^ | 两位不同时结果为 111,相同时为 000。 |
| 左移 | Left Shift | << | 向左移动 NNN 位,相当于乘以 2N2^N2N。 |
| 右移 | Right Shift | >> | 向右移动 NNN 位,相当于整数除以 2N2^N2N。 |
B. if、for 和 while 的区分与记忆
它们都是控制流 (Control Flow) 语句,用于控制程序执行的顺序。
| 语句 | 英文名称/词源 | 作用 | 核心记忆点 |
|---|---|---|---|
if | Condition(条件) | 决策:根据一个或多个条件是否成立,执行相应的代码块。 | “如果” (If):判断是否执行。 |
for | Iterate(迭代) | 遍历:针对一个已知的序列(如列表、字符串、固定次数的范围),依次处理序列中的每一个元素。 | “针对每个” (For Each):次数已知,用于遍历。 |
while | Loop(循环) | 循环:只要给定的条件持续为真,就重复执行代码块,直到条件不满足。 | “当…时” (While):次数未知,依赖条件变化终止。 |
| 场景 | 您应该用哪个? |
|---|---|
| 判断用户输入是否有效。 | if (判断条件) |
| 打印列表中的所有学生姓名。 | for (遍历列表) |
| 计算 NNN 转换为 000 之前被除以 222 的次数。 | while (次数不固定,依赖 N>0N>0N>0 这个条件) |
| 对一个数组进行 101010 次操作。 | for (次数已知,range(10)) |
在 OJ/ACM 比赛中,程序的输入和输出通常需要完全符合题目要求,核心区别在于:
- 输入不是交互式的:程序通常需要持续读取多行或多组输入,直到输入结束(EOF, End Of File)。
- 输出必须是纯净的:不能有任何额外的提示性文字(比如
请输入...或十进制数 ... 转换为...)。最终的输出结果必须是精确且唯一的。
ACM/OJ 格式下的实现
1. 核心函数(保持不变)
函数本身是正确的,只是需要去掉打印语句。
def solve_count_ones(n):"""核心计算逻辑:使用内置函数计算二进制中 1 的个数。(在 OJ 环境下,我们通常假设输入是符合预期的非负整数)"""# 使用 bin() 转换为二进制字符串,然后用 count('1') 计数return bin(n).count('1')
2. 标准 ACM/OJ 主程序结构
由于 OJ 系统通常通过 EOF (End Of File) 来判断输入是否结束,Python 中最常见的处理方式是使用 sys.stdin.read().split() 或在 try-except 结构中使用 input() 或 sys.stdin。
方法一:适用于多行输入 (推荐)
使用 sys 模块,一次性读取所有输入并处理:
import sysdef solve_count_ones(n):"""核心计算逻辑"""# 避免负数检查和额外的打印语句,只返回结果# 如果题目有明确的输入范围限制,这里可以省略 try-exceptreturn bin(n).count('1')def main_acm():# 读入所有输入数据,并按空格或换行符分割成列表# 列表中的每个元素都是一个字符串格式的数字input_data = sys.stdin.read().split()# 遍历列表中的每一个数据for data_str in input_data:# 排除空字符串(如果输入有额外的空行)if not data_str:continuetry:# 将字符串转换为整数n = int(data_str)# 调用核心函数计算结果result = solve_count_ones(n)# 【关键】直接打印结果,不带任何额外文字print(result)except ValueError:# 如果遇到非数字输入,通常在 OJ 环境下可以忽略或根据题目要求处理continue# 运行时调用主函数
# main_acm()
方法二:使用 while True 循环读取每行输入
这种方法适用于题目明确规定每次只输入一个数字并换行的情况。
# 方法二的实现,适用于每行一个测试用例
def main_acm_per_line():while True:try:# 尝试读取一行输入line = input()# 如果输入为空或结束,则退出循环if not line:breakn = int(line)# 核心计算:bin(n).count('1')result = bin(n).count('1')# 【关键】纯净输出print(result)except EOFError:# 捕获 EOF (End Of File),表示输入已全部读取完毕breakexcept ValueError:# 捕获输入转换错误,通常也选择退出或跳过break# main_acm_per_line()
总结关键区别
| 特性 | 交互式/日常函数 | ACM/OJ 格式 |
|---|---|---|
| 输入方式 | input("请输入数字:") | 使用 sys.stdin.read() 或 while True: input() 循环读取。 |
| 输入次数 | 通常一次 | 持续读取多组测试用例,直到文件末尾 (EOF)。 |
| 输出 | 包含提示信息、中间步骤(如 print(f"十进制数..."))。 | 纯净,只输出最终的结果数字。 |
| 错误处理 | 需要友好地提示用户错误(如 return "输入必须是非负整数")。 | 简化错误处理,假设输入格式正确,或在 try-except 中静默退出。 |
