使用Python实现一个函数,用于将十进制数(Decimal )转换为二进制数(Binary),并计算二进制表示中"1"的个数。
Python 实现
这里提供三种不同的 Python 实现方法:
方法一:使用 Python 内置函数 bin() 和 count() (最简洁)
Python 的内置函数 bin() 可以直接将整数转换为以 '0b' 开头的二进制字符串,然后使用字符串的 count() 方法计算 '1' 的数量。
python
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) 操作来消除数字 n n n 最右边的 '1',直到 n n n 变为 0。循环的次数即为 '1' 的个数。
- 位运算 (Bitwise Operation) :
- 解释 :直接对数字在内存中的二进制位进行操作的运算,比如"与"(AND,
&)、"或"(OR,|)、"非"(NOT,~)和"异或"(XOR,^)。 - 词源来历 :由 Bit (位,即二进制数字 0 或 1)和 Operation(操作)组成。
- 解释 :直接对数字在内存中的二进制位进行操作的运算,比如"与"(AND,
python
def count_ones_in_binary_bitwise(decimal_num):
"""
使用位运算(Brian Kernighan 算法)计算十进制数转换为二进制后 1 的个数。
Args:
decimal_num (int): 要转换的十进制非负整数。
Returns:
int: 二进制表示中 1 的个数。
"""
if decimal_num < 0:
return "输入必须是非负整数"
count = 0
n = decimal_num
# 当 n 不为 0 时循环
while n > 0:
# n & (n - 1) 的作用是消除 n 最右边的一个 '1'
n = n & (n - 1)
count += 1
return 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,意为"小测量,小尺度",常指代这种求余数的运算。
python
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 0
count = 0
n = decimal_num
while n > 0:
# 取余数:n % 2,如果余数是 1,则计数器加 1
if n % 2 == 1:
count += 1
# 整数除法:n // 2,相当于向右移位
n = n // 2
return 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 就是"计数"的意思,非常好记。无论是在字符串(统计字符)还是列表(统计元素)中,它都用于统计数量。 |
记忆技巧:结合应用场景
将这两个函数放在一起记忆,因为它们在"数 1 1 1 的个数"这个场景下是完美组合:
- 第一步(转换) :我需要把数字变成二进制,所以用
bin()。 - 第二步(计数) :我需要数里面的 1 1 1,所以用字符串的
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 ,即 0 0 0 或 1 1 1)进行操作的运算。它比普通的加减乘除运算更快,因为它是硬件级别的操作。
- 常用 :在需要极致性能(如嵌入式开发、图形学)、加密算法、以及高效处理整数(如您遇到的数 1 1 1 的个数)时,位运算非常常用且高效。
| 运算符 | 英文名称 | 符号 | 作用 |
|---|---|---|---|
| 按位与 | AND | & |
两位都为 1 1 1 时结果为 1 1 1,否则为 0 0 0。 |
| 按位或 | OR | ` | ` |
| 按位异或 | XOR | ^ |
两位不同时结果为 1 1 1,相同时为 0 0 0。 |
| 左移 | Left Shift | << |
向左移动 N N N 位,相当于乘以 2 N 2^N 2N。 |
| 右移 | Right Shift | >> |
向右移动 N N N 位,相当于整数除以 2 N 2^N 2N。 |
B. if、for 和 while 的区分与记忆
它们都是控制流 (Control Flow) 语句,用于控制程序执行的顺序。
| 语句 | 英文名称/词源 | 作用 | 核心记忆点 |
|---|---|---|---|
if |
Condition(条件) | 决策:根据一个或多个条件是否成立,执行相应的代码块。 | "如果" (If) :判断是否执行。 |
for |
Iterate(迭代) | 遍历 :针对一个已知的序列(如列表、字符串、固定次数的范围),依次处理序列中的每一个元素。 | "针对每个" (For Each) :次数已知,用于遍历。 |
while |
Loop(循环) | 循环 :只要给定的条件持续为真,就重复执行代码块,直到条件不满足。 | "当...时" (While) :次数未知,依赖条件变化终止。 |
| 场景 | 您应该用哪个? |
|---|---|
| 判断用户输入是否有效。 | if (判断条件) |
| 打印列表中的所有学生姓名。 | for (遍历列表) |
| 计算 N N N 转换为 0 0 0 之前被除以 2 2 2 的次数。 | while (次数不固定,依赖 N > 0 N>0 N>0 这个条件) |
| 对一个数组进行 10 10 10 次操作。 | for (次数已知,range(10)) |
在 OJ/ACM 比赛中,程序的输入和输出通常需要完全符合题目要求,核心区别在于:
- 输入不是交互式的 :程序通常需要持续读取多行或多组输入 ,直到输入结束(EOF, End Of File)。
- 输出必须是纯净的 :不能有任何额外的提示性文字(比如
请输入...或十进制数 ... 转换为...)。最终的输出结果必须是精确 且唯一的。
ACM/OJ 格式下的实现
1. 核心函数(保持不变)
函数本身是正确的,只是需要去掉打印语句。
python
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 模块,一次性读取所有输入并处理:
python
import sys
def solve_count_ones(n):
"""核心计算逻辑"""
# 避免负数检查和额外的打印语句,只返回结果
# 如果题目有明确的输入范围限制,这里可以省略 try-except
return bin(n).count('1')
def main_acm():
# 读入所有输入数据,并按空格或换行符分割成列表
# 列表中的每个元素都是一个字符串格式的数字
input_data = sys.stdin.read().split()
# 遍历列表中的每一个数据
for data_str in input_data:
# 排除空字符串(如果输入有额外的空行)
if not data_str:
continue
try:
# 将字符串转换为整数
n = int(data_str)
# 调用核心函数计算结果
result = solve_count_ones(n)
# 【关键】直接打印结果,不带任何额外文字
print(result)
except ValueError:
# 如果遇到非数字输入,通常在 OJ 环境下可以忽略或根据题目要求处理
continue
# 运行时调用主函数
# main_acm()
方法二:使用 while True 循环读取每行输入
这种方法适用于题目明确规定每次只输入一个数字并换行的情况。
python
# 方法二的实现,适用于每行一个测试用例
def main_acm_per_line():
while True:
try:
# 尝试读取一行输入
line = input()
# 如果输入为空或结束,则退出循环
if not line:
break
n = int(line)
# 核心计算:bin(n).count('1')
result = bin(n).count('1')
# 【关键】纯净输出
print(result)
except EOFError:
# 捕获 EOF (End Of File),表示输入已全部读取完毕
break
except ValueError:
# 捕获输入转换错误,通常也选择退出或跳过
break
# main_acm_per_line()
总结关键区别
| 特性 | 交互式/日常函数 | ACM/OJ 格式 |
|---|---|---|
| 输入方式 | input("请输入数字:") |
使用 sys.stdin.read() 或 while True: input() 循环读取。 |
| 输入次数 | 通常一次 | 持续读取多组测试用例,直到文件末尾 (EOF)。 |
| 输出 | 包含提示信息、中间步骤(如 print(f"十进制数..."))。 |
纯净,只输出最终的结果数字。 |
| 错误处理 | 需要友好地提示用户错误(如 return "输入必须是非负整数")。 |
简化错误处理,假设输入格式正确,或在 try-except 中静默退出。 |