Q1: 赛跑
下面的 race
函数有时会返回错误的值,有时会永远运行。
def race(x, y):
"""The tortoise always walks x feet per minute, while the hare repeatedly
runs y feet per minute for 5 minutes, then rests for 5 minutes. Return how
many minutes pass until the tortoise first catches up to the hare.
>>> race(5, 7) # After 7 minutes, both have gone 35 steps
7
>>> race(2, 4) # After 10 minutes, both have gone 20 steps
10
"""
assert y > x and y <= 2 * x, 'the hare must be fast but not too fast'
tortoise, hare, minutes = 0, 0, 0
while minutes == 0 or tortoise - hare:
tortoise += x
if minutes % 10 < 5:
hare += y
minutes += 1
return minutes
在 61A 代码编辑器里运行 找到满足以下任一条件的正整数 x
和 y
(其中 y
大于 x
,但不超过 2 * x
):
race(x, y)
返回错误的值;或race(x, y)
永远运行。
您只需找到一组满足任一条件的数字即可完成此题;当然,您也可以尝试寻找更多组合。
提示:
- 当
x
被赋值为一个数字时,x += 1
与x = x + 1
相同。 - 0 是一个假值,所有其他数字都是真值。
[提示]
当乌龟不是第一次追上兔子时,race(x, y)
的结果才是错误的。尝试一些小于5的较小数字,看看是否能找到这样一种情况:tortoise
已经大于 hare
,但此时 tortoise - hare
的值并不为零。
将您找到的 (x, y)
示例发布到小组语音频道中的文本聊天中。如果遇到困难超过十分钟,请及时寻求帮助!
解答:
代码中的循环条件是 while minutes == 0 or tortoise - hare:
。
minutes == 0
确保循环至少执行一次。tortoise - hare
是关键。在 Python 中,任何非零数字都被视为True
(真值),只有0
被视为False
(假值)。所以,while tortoise - hare:
等价于while tortoise != hare:
。
这意味着,循环只有在乌龟和兔子的路程(tortoise 和 hare)完全相等时才会停止。
然而,题目要求的是“乌龟第一次追上兔子(the tortoise first catches up to the hare)”的时刻。在现实中,“追上”意味着乌龟的路程大于或等于兔子的路程。代码错误地将这个条件简化为了严格等于。
这种偏差会导致两种错误:
- 返回错误的值:乌龟可能先是超过了兔子(
tortoise > hare
),然后由于兔子开始跑,差距又被拉开,直到未来的某个时刻,两者的路程才恰好相等。这时函数返回的是后面这个“恰好相等”的时刻,而不是第一次“追上或超过”的时刻。 - 永远运行(死循环):乌龟的路程可能永远无法恰好等于兔子的路程。它可能在某一分钟还落后于兔子,下一分钟就直接超过了兔子,两者路程的差值从一个负数直接跳到一个正数,完美地“跨过”了零。
1. 导致“永远运行”的例子:race(3, 5)
我们来手动跟踪一下 race(3, 5)
的执行过程。
x = 3
(乌龟速度)y = 5
(兔子速度)- 约束条件检查:
5 > 3
(True) and5 <= 2 * 3
(True)。满足条件。
Minutes | minutes % 10 < 5 ? |
Tortoise (乌龟) | Hare (兔子) | tortoise - hare |
说明 |
---|---|---|---|---|---|
初始 | 0 | 0 | 0 | 循环开始 (minutes == 0 ) |
|
1 | True (跑) | 3 | 5 | -2 | |
2 | True (跑) | 6 | 10 | -4 | |
3 | True (跑) | 9 | 15 | -6 | |
4 | True (跑) | 12 | 20 | -8 | |
5 | True (跑) | 15 | 25 | -10 | |
6 | False (歇) | 18 | 25 | -7 | |
7 | False (歇) | 21 | 25 | -4 | |
8 | False (歇) | 24 | 25 | -1 | |
9 | False (歇) | 27 | 25 | 2 | 乌龟超过了兔子!但差值不为0,循环继续 |
10 | False (歇) | 30 | 25 | 5 | |
11 | True (跑) | 33 | 30 | 3 | 兔子又开始跑了 |
12 | True (跑) | 36 | 35 | 1 | |
13 | True (跑) | 39 | 40 | -1 | 兔子又超过了乌龟 |
你会发现,在第9分钟,乌龟的路程(27)已经超过了兔子(25),但它们的差值是2,不为0。循环没有停止。之后,它们的差值永远无法回到0。乌龟和兔子的路程差值会不断在正负数之间跳跃,但永远不会恰好是0。
因此,race(3, 5)
会导致一个无限循环。
2. 导致“返回错误值”的例子:race(4, 6)
我们再来跟踪一下 race(4, 6)
的执行过程。
x = 4
(乌龟速度)y = 6
(兔子速度)- 约束条件检查:
6 > 4
(True) and6 <= 2 * 4
(True)。满足条件。
Minutes | minutes % 10 < 5 ? |
Tortoise (乌龟) | Hare (兔子) | tortoise - hare |
说明 |
---|---|---|---|---|---|
... | ... | ... | ... | ... | (前面几步省略) |
7 | False (歇) | 28 | 30 | -2 | |
8 | False (歇) | 32 | 30 | 2 | 乌龟第一次追上(并超过)兔子!正确答案应为 8 |
9 | False (歇) | 36 | 30 | 6 | 差值不为0,循环继续 |
10 | False (歇) | 40 | 30 | 10 | |
11 | True (跑) | 44 | 36 | 8 | |
12 | True (跑) | 48 | 42 | 6 | |
13 | True (跑) | 52 | 48 | 4 | |
14 | True (跑) | 56 | 54 | 2 | |
15 | True (跑) | 60 | 60 | 0 | 路程相等!循环停止,函数返回 15 |
在这个例子中:
- 在第8分钟,乌龟的路程(32)第一次超过了兔子(30)。这才是题目意义上的“第一次追上”,所以正确答案应该是
8
。 - 但是因为代码检查的是
tortoise == hare
,循环没有在第8分钟停止。 - 直到第15分钟,两者的路程才恰好都为60。此时循环停止,函数返回
15
。
这是一个错误的值,因为它不是第一次追上的时间。
Q2: Fizzbuzz
实现经典的 Fizz Buzz 序列。 fizzbuzz
函数接受一个正整数 n
,并为 1 到 n
之间的每个整数打印一行输出。 对于每个 i
:
- 如果
i
可以同时被 3 和 5 整除,则打印fizzbuzz
。 - 如果
i
可以被 3 整除(但不能被 5 整除),则打印fizz
。 - 如果
i
可以被 5 整除(但不能被 3 整除),则打印buzz
。 - 否则,打印数字
i
。
尝试使您的 fizzbuzz
实现简洁。
def fizzbuzz(n):
"""
>>> result = fizzbuzz(16)
1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fizzbuzz
16
>>> print(result)
None
"""
"*** YOUR CODE HERE ***"
Run in 61A Code
[提示]
请注意 if
和 elif
子句的顺序:首先尝试检查当前数字是否可以同时被 3 和 5 整除,然后检查是否仅能被 3 整除以及是否仅能被 5 整除。
解答:
def fizzbuzz(n):
"""
>>> result = fizzbuzz(16)
1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fizzbuzz
16
>>> print(result)
None
"""
i = 1
while i <= n:
if i % 3 == 0 and i % 5 == 0:
print("fizzbuzz")
elif i % 3 == 0:
print("fizz")
elif i % 5 == 0:
print("buzz")
else:
print(i)
i = i + 1
return None
Q3:是素数吗?
编写一个函数,如果正整数 n
是素数,则返回 True
,否则返回 False
。
素数 n 是一个除了 1 和 n 本身之外不能被任何数字整除的数字。 例如,13 是素数,因为它只能被 1 和 13 整除,但 14 不是,因为它能被 1、2、7 和 14 整除。
使用 %
运算符:x % y
返回 x
除以 y
的余数。
[提示]
以下是一个 while
循环,它会遍历所有大于 1 且小于 n
的整数:
i = 2
while i < n:
...
i = i + 1
可以使用 n % i == 0
来判断 i
是否是 n
的因子。 如果是,则 return False
。
def is_prime(n):
"""
>>> is_prime(10)
False
>>> is_prime(7)
True
>>> is_prime(1) # one is not a prime number!!
False
"""
"*** YOUR CODE HERE ***"
在 61A 代码中运行
展示时间:请用一句话概括你们解决 is_prime
问题所使用的思路,确保即使不看代码也能理解。 选出一位同学来讲解,然后在 Discord 的 discuss-queue
频道发送带有 @discuss
标签的消息,内容包括你们的小组编号和 “Prime Time!”。 助教或老师会加入你们的语音频道,听取讲解并给出反馈。
解答:
def is_prime(n):
"""
>>> is_prime(10)
False
>>> is_prime(7)
True
>>> is_prime(1) # one is not a prime number!!
False
"""
if n == 1:
return False
else:
i = 2
while i < n:
if n % i == 0:
return False
i = i + 1
return True
Q4:唯一数字
编写一个函数,返回正整数中唯一数字的个数。
[提示]
您可以使用 //
和 %
将一个正整数分成它的个位数和其余的数字。
建议先定义一个函数 has_digit(n, k)
,用来判断数字 n
是否包含数字 k
。
def unique_digits(n):
"""Return the number of unique digits in positive integer n.
>>> unique_digits(8675309) # All are unique
7
>>> unique_digits(13173131) # 1, 3, and 7
3
>>> unique_digits(101) # 0 and 1
2
"""
"*** YOUR CODE HERE ***"
def has_digit(n, k):
"""Returns whether k is a digit in n.
>>> has_digit(10, 1)
True
>>> has_digit(12, 7)
False
"""
assert k >= 0 and k < 10
"*** YOUR CODE HERE ***"
在 61A 代码中运行 一种方法是循环遍历从 0 到 9 的每个数字,并检查 n
是否包含该数字。然后数数看总共有多少个不同的数字。
解答:
def unique_digits(n):
"""Return the number of unique digits in positive integer n.
>>> unique_digits(8675309) # All are unique
7
>>> unique_digits(13173131) # 1, 3, and 7
3
>>> unique_digits(101) # 0 and 1
2
"""
unique = 0
while n > 0:
k = n % 10
n = n // 10
if not has_digit(n,k):
unique = unique + 1
return unique
def has_digit(n, k):
"""Returns whether k is a digit in n.
>>> has_digit(10, 1)
True
>>> has_digit(12, 7)
False
"""
assert k >= 0 and k < 10
while n > 0:
last = n % 10
n = n // 10
if last == k:
return True
return False
Comments NOTHING