题目要求:

给定一个正整数N,你需要输出所有长度为N的二进制序列(即只包含 01 的字符串)。

  • 输出顺序:必须按照字典序(从小到大)排列。例如,当 $N=2$ 时,顺序应为 00, 01, 10, 11

  • 格式:每行输出一个二进制字符串。

  • 解题方法限制

  1. 递归回溯法(Recursive search/backtracking)。
  2. 二进制加 1 法(通过模拟二进制加法从 $0$ 一直加到 $2^N-1$)。
输入 输出
2 00
01
10
11

我写的代码:

1
2
3
4
5
6
7
haha = int(input())
figure = [0,1]
result = [f"{a}{b}{c}{d}{e}{f}{g}{h}{i}{j}{k}{l}{m}{n}{o}"for a in figure for b in figure for c in figure for d in figure for e in figure for f in figure for g in figure for h in figure for i in figure for j in figure for k in figure for l in figure for m in figure for n in figure for o in figure]

for i in range(2**haha):
print(result[i][15-haha:])

巧妙地利用了多重循环遍历嵌套,以及后面的切片操作

这就是所谓的力大飞砖


现在来看正确的写法

“二进制加 1”法

1
2
3
4
5
n = int(input())
# 1 << n 相当于 2 的 n 次方。从 0 遍历到 (2^n) - 1
for i in range(1 << n):
# :0{n}b 意思是转为二进制 (b),不足 n 位的在前面补 0
print(f"{i:0{n}b}")

这种方法的逻辑是什么?

题目需要我输出所有长度为N的二进制序列,而这些序列恰好是把从 0 到 $2^n-1$ 的所有十进制数字,依次转化为二进制。

1. 1 << n:极其高效的“$2^n$”计算器

<<左移运算符(Bitwise Left Shift)。这个操作在 C 语言里也是一模一样的

它的核心意思是:把数字 1 的二进制形式,整体向左移动 n 位,右边空出来的位置补零。

我们来推演一下:

数字 1 的二进制就是 1

  • 如果 n = 11 << 1,二进制变成 10,换算成十进制就是 2 ($2^1$)。
  • 如果 n = 21 << 2,二进制变成 100,换算成十进制就是 4 ($2^2$)。
  • 如果 n = 31 << 3,二进制变成 1000,换算成十进制就是 8 ($2^3$)。

所以,1 << n 在数学上等价于 $2^n$。

代码里的 range(1 << n),如果输入 $N=3$,就等价于 range(8),这会让变量 i0 一直遍历到 7。这刚好覆盖了长度为 3 的二进制序列对应的所有十进制数。


2. f"{i:0{n}b}":Python 里的超级“printf”

这是 Python 里的 f-string(格式化字符串),作用类似于 C 语言里的 printf,但功能更强大。

在 C 语言里,如果你想输出一个固定宽度、前面补零的十进制数,你会写 printf("%04d", i)。但是在标准的 C 语言(C23 标准之前)里,并没有直接输出二进制的占位符(没有 %b 这种东西),真要输出二进制,还得自己写个循环用掩码逐位提取 01

而 Python 把这件事直接做成了内置功能。我们把 {i:0{n}b} 拆开来看:

  • f"...":外面的 f 告诉 Python,这不是一个普通的字符串,里面如果有大括号 {},要把它当成变量或表达式去计算。
  • i:这是当前循环到的十进制数字(比如 0, 1, 2, 3…)。
  • ::这是一个分隔符。冒号左边是要处理的“变量名”,冒号右边是“格式化规则”。
  • b:代表 binary(二进制)。这会让 Python 自动把十进制的 i 转换成二进制。比如 i 是 2,转出来就是 "10"
  • 0{n}:这是控制“对齐和补零”的。
    • {n}:表示输出的总宽度。这里巧妙地嵌套了另一个变量 n(也就是我们输入的序列长度)。
    • 0:表示如果二进制字符串的长度不够这个宽度,就在左边补零

”递归回溯“法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def generate_binary(n, current_str=""):
# 终止条件:如果当前字符串长度已经达到了 n,就打印并结束这一条分支
if len(current_str) == n:
print(current_str)
return

# 递归分支:当前位置先尝试填 '0',然后继续往下生成
generate_binary(n, current_str + "0")

# 递归分支:尝试完 '0' 之后,再尝试填 '1',继续往下生成
generate_binary(n, current_str + "1")

# 接收输入并触发函数
haha = int(input())
generate_binary(haha)

为什么传了一个参数,却有两个变量?

在 Python 里,current_str="" 这个语法叫做默认参数

以前写 C 语言的时候,函数如果定义了接收两个参数,调用时就必须老老实实传两个,少一个编译器都会报错。但 Python 很灵活,它允许你给参数“兜底”。当你只传了 n 的时候,Python 发现你没传第二个参数,就会自动帮你把 current_str 赋值为默认的空字符串 ""

然而,默认参数不会导致变量被重新初始化,默认参数就像是备胎(兜底),只有你不给它传值的时候,它才会起作用;一旦你传了值,它就乖乖让位