def fastest_words(game):
"""Return a list of lists of which words each player typed fastest.
Arguments:
game: a game data abstraction as returned by time_per_word.
>>> p0 = [5, 1, 3]
>>> p1 = [4, 1, 6]
>>> fastest_words(game(['Just', 'have', 'fun'], [p0, p1]))
[['have', 'fun'], ['Just']]
"""
player_indices = range(len(all_times(game))) # contains an *index* for each player
word_indices = range(len(all_words(game))) # contains an *index* for each word
# BEGIN PROBLEM 10
"*** YOUR CODE HERE ***"
"""
对于每个word,检索当前index的所有player中耗时min的player_index,对应的list添加上words_at(index)
"""
fastest_words_list = [[] for _ in word_indices]
times = all_times(game)
for i in word_indices:
min_word_index = min(player_indeices, key = lambda x: times[x][i]) #这句话很关键 注意如何挑选出list中value最小值的index 将整个index通过range(len())形式遍历
fastest_words_list[min_word_index].append(words_at(game, i))
return fastest_words_list
记录一下cs61A学习过程中的有趣代码
运行命令行
python -i xxx.py #正常运行代码(也会运行doctest 但是不会具体显示测试情况 fail也会报错)
python -m doctest -v xxx.py #运行代码+显示doctest测试情况
python ok -q --suite x --case y --local #使用ok测试代码(不需要具体case就把--suite x --case y去除)
python ok -q xxx(函数名) #用doctest测试单个函数
每个test除了数值外可选的回答:
Function
Infinite
Nothing
Error
Lecture 4 High Order Function
lambda + inverse函数,对于函数f,如果存在非负整数x使f(x) ==y,则输出g函数,使g(y)->x
def search(f):
x = 0
while True:
if f(x): #执行时相当于调用了lambda: f(x) == y,return f(x) == y,该语句可以等效为if f(x) ==y:
return x
x = x + 1
def inverse(f):
"""Reverse g(y) such that g(f(x)) -> x
>>> from math import sqrt
>>> square = inverse(sqrt)
>>> square(16)
256
"""
return lambda y: search(lambda x: f(x) == y)
Exam prep01
比较复杂的一种写法
"""
相当于一个for循环,输入n, k, 判断 k % 2 ==0 or ... or k % n ==0
"""
def div_by_primes_under(n):
"""
>>> div_by_primes_under(10)(11)
False
>>> div_by_primes_under(10)(121)
False
>>> div_by_primes_under(10)(12)
True
>>> div_by_primes_under(5)(1)
False
"""
checker = lambda x: False
i = 2
while i <= n:
if not checker(i): # 简便了一下k % 2 ==0 or ... or k % n ==0,例如i = 4时, x % 4必有x % 2,此时不需要更新checker,该判断条件不要也可以
checker = (lambda f, i: lambda x: x % i == 0 or f(x))(checker, i)
i = i + 1
return checker
def div_by_primes_under_no_lambda(n):
"""
>>> div_by_primes_under_no_lambda(10)(11)
False
>>> div_by_primes_under_no_lambda(10)(121)
False
>>> div_by_primes_under_no_lambda(10)(12)
True
>>> div_by_primes_under_no_lambda(5)(1)
False
"""
def checker(x):
return False
i = 2
while i <= n:
if not checker(i):
def outer(f, i):
def inner(x):
return x % i == 0 or f(x)
return inner
i = i + 1
return checker
def three_memory(n):
"""
>>> f = three_memory('first')
>>> f = f('first')
Not found
>>> f = f('second')
Not found
>>> f = f('third')
Not found
>>> f = f('second') # 'second' was not input three calls ago
Not found
>>> f = f('second') # 'second' was input three calls ago
Found
>>> f = f('third') # 'third' was input three calls ago
Found
>>> f = f('third') # 'third' was not input three calls ago
Not found
"""
def f(x, y, z):
def g(i):
if i == x:
print('Found')
else:
print('Not found')
return f(y, z, i)
return g
return f('None', 'None', n)
Lecture 9 Tree Recursion
Linear recursion:每次递归仅执行一次递归调用
Tree recursion:每次递归执行多次调用,使每一个树枝有多个分支
这篇博客写得很详细【菜gou的CS61A学习笔记7 Tree Recursion】_cs61a tree-CSDN博客
"""
cascade(123):
123
12
1
12
123
"""
"""第一种写法"""
def cascade(n):
if n < 10:
print(n)
else:
print(n)
cascade(n // 10)
print(n)
"""更简洁点的写法"""
def cascade_new(n):
print(n)
if n >= 10:
print(n)
cascade(n // 10)
print(n)
"""与cascade作用相反"""
def inverse_cascade(n):
grow(n)
print(n)
shrink(n)
def f_then_g(f, g, n):
if n:
f(n)
g(n)
grow = lambda n: f_then_g(grow, print, n//10)
shrink = lambda n: f_then_g(print, shrink, n//10)
斐波那契数列
def fabonaci(n):
if n == 0:
return 0
if n == 1:
return 1
else:
return fabonaci(n - 1) + fabonaci(n - 2)
汉诺塔问题
"""
三根柱子的汉诺塔问题
对于n个disks移动问题,分解成先把第n - 1个disk移动到剩余的空闲位,然后把第n个disk从起点移到终点,再把第n - 1个disk从空闲位移动回来
"""
def move_disk(disk_number, from_peg, to_peg):
print("Move disk" + str(disk_number) + "from peg" + str(from_peg) + "to peg" + str(to_peg))
def solve_hano(n, start_peg, end_peg):
if n == 1:
move_disk(n, start_peg, end_peg)
else:
spare_peg = 6 - start_peg - end_peg
solve_hano(n-1, start_peg, spare_peg) #在这一步,信任前面的n-1个disc被挪到了spare_peg
move_disk(n, start_peg, end_peg)
solve_hano(n-1, spare_peg, end_peg)
"""
汉诺塔的另一种写法,来自hw03
"""
def print_move(origin, destination):
"""Print instructions to move a disk."""
print("Move the top disk from rod", origin, "to rod", destination)
def move_stack(n, start, end):
"""Print the moves required to move n disks on the start pole to the end
pole without violating the rules of Towers of Hanoi.
n -- number of disks
start -- a pole position, either 1, 2, or 3
end -- a pole position, either 1, 2, or 3
There are exactly three poles, and start and end must be different. Assume
that the start pole has at least n disks of increasing size, and the end
pole is either empty or has a top disk larger than the top n start disks.
>>> move_stack(1, 1, 3)
Move the top disk from rod 1 to rod 3
>>> move_stack(2, 1, 3)
Move the top disk from rod 1 to rod 2
Move the top disk from rod 1 to rod 3
Move the top disk from rod 2 to rod 3
>>> move_stack(3, 1, 3)
Move the top disk from rod 1 to rod 3
Move the top disk from rod 1 to rod 2
Move the top disk from rod 3 to rod 2
Move the top disk from rod 1 to rod 3
Move the top disk from rod 2 to rod 1
Move the top disk from rod 2 to rod 3
Move the top disk from rod 1 to rod 3
"""
assert 1 <= start <= 3 and 1 <= end <= 3 and start != end, "Bad start/end"
"*** YOUR CODE HERE ***"
if n == 1:
print_move(start, end)
else:
move_stack(n - 1, start, 6 - start - end)
move_stack(1, start, end)
move_stack(n - 1, 6 - start - end, end)
"""
counting_partition: 对输入数n,划分为几个数相加,其中的最大数不超过k
问题分解n, 最大数k - 1分解以及 n - k,最大数k分解
"""
def counting_partition(n, k):
if n == 0:
return 1 #n = 0时return 1,因为调用它的上一层(n, n)即n + 0一种划分,到底了
elif n < 0:
return 0 #递归越界
elif k == 0:
return 0 #无法进行划分
else:
return counting_partition(n, k - 1) + counting_partition(n - k, k)
"""
计算change能有多少种分为25, 10, 5, 1 coin的方法
和counting_partition的写法很类似
"""
def get_next_coin(coin):
if n == 1:
return 5
elif n == 5:
return 10
elif n == 10:
return 25
else:
return None
# 当每次循环所需要传递(跟踪)的参数大于1时,则需要在该recursion函数内部定义一个helper函数
# 通过原函数来初始化helper函数,在helper函数内完成recursion
def count_coins(change):
def count(change, smallestCoin):
if change == 0:
return 1
elif change < 0 or smallestCoin == None: #可以优化为elif smallestCoin == None or change < smallestCoin:
return 0
else:
return count(change, get_next_coin(smallestCoin)) + count(change - smallestCoin, smallestCoin)
return count(change, 1)
"""
count_coins的另一种写法
从最大的coin开始往下分,tree的一支是使用largestCoin(则对剩余的coin继续分割),另一支是不使用最大的coin,使用下一层更小的coin分割
"""
def largest_coin(coin):
if coin >= 25:
return 25
elif coin >= 10:
return 10
elif coin >= 5:
return 5
elif coin >= 1:
return 1
else:
return None
def get_next_coin(coin):
"""Return the next coin.
>>> get_next_coin(1)
5
>>> get_next_coin(5)
10
>>> get_next_coin(10)
25
>>> get_next_coin(2) # Other values return None
"""
if coin == 25:
return 10
elif coin == 10:
return 5
elif coin == 5:
return 1
def count_coins(change):
"""Return the number of ways to make change using coins of value of 1, 5, 10, 25.
>>> count_coins(15)
6
>>> count_coins(10)
4
>>> count_coins(20)
9
>>> count_coins(100) # How many ways to make change for a dollar?
242
>>> from construct_check import check
>>> # ban iteration
>>> check(HW_SOURCE_FILE, 'count_coins', ['While', 'For'])
True
"""
"*** YOUR CODE HERE ***"
# def count(change, smallestCoin):
# if change == 0:
# return 1
# elif smallestCoin == None or change < smallestCoin:
# return 0
# return count(change, get_next_coin(smallestCoin)) + count(change - smallestCoin, smallestCoin)
# return count(change, 1)
def count(change, largestCoin):
print("DEBUG: change, largestCoin", change, largestCoin)
if change == 0 or largestCoin == 1:
# print("DEBUG: change, largestCoin", change, largestCoin)
return 1
elif change < 0:
# print("DEBUG: change, largestCoin", change, largestCoin)
return 0
return count(change, get_next_coin(largestCoin)) + count(change - largestCoin, largestCoin)
return count(change, largest_coin(change))
Lambda函数实现自己递归:需要在lambda函数内部将lambda函数作为参数传入
"""
传入参数n,返回值n!
"""
from operator import sub, mul
"""
>>> from operator import sub, mul
>>> fact = lambda n: 1 if n == 1 else mul(1, fact(sub(n, 1)))
>>> fact(5)
120
"""
def make_anonymous_factorial():
"""Return the value of an expression that computes factorial.
>>> make_anonymous_factorial()(5)
120
>>> from construct_check import check
>>> # ban any assignments or recursion
>>> check(HW_SOURCE_FILE, 'make_anonymous_factorial', ['Assign', 'AugAssign', 'FunctionDef', 'Recursion'])
True
"""
"""
本来我写的,这样写有个问题是最后mul(n, f(n - 1))这里f没有define,所以应该将f本身也作为参数传递下去
return (lambda f: lambda n: 1 if n == 1 else mul(n, f(n - 1)))(lambda n: 1 if n == 1 else mul(n, f(n - 1)))"""
return (lambda f: lambda n: 1 if n == 1 else mul(n, f(f, n - 1)))(lambda f, n: 1 if n == 1 else mul(n, f(f, n - 1)))
Lecture 10
pairs = [[1, 2], [3, 4], [4, 5], [5, 5], [10, 10]]
same_count = 0
for x, y in pairs:
if x == y:
same_count += 1
print(same_count)
"""
将输入的两个数(数本身就是降序的),每个位数降序排列组合成一个数
还有一种写法是,先判断两个数哪个更大,递归条件是偏小的n//10 < 0,
然后将偏小数的每一位插入偏大数的位数中
或者比较个位数,个位数偏小的数n // 10,传递下去(本种写法)
"""
def merge(n1, n2):
""" Merges two numbers by digit in decreasing order
>>> merge(31, 42)
4321
>>> merge(21, 0)
21
>>> merge (21, 31)
3211
"""
def helper(result, n1, n2):
if (n1 == 0 and n2 < 10) or (n1 < 10 and n2 == 0):
return result * 10 + n2 if n1 == 0 else result * 10 + n1
else:
last_digit_1 = n1 % 10
last_digit_2 = n2 % 10
if last_digit_1 <= last_digit_2:
result = result * 10 + last_digit_1
return helper(result, n1 // 10, n2)
else:
result = result * 10 + last_digit_2
return helper(result, n1, n2 // 10)
if n1 == 0 or n2 == 0:
return n2 if not n1 else n1
return helper(0, n1, n2)
print(merge (531, 0))
"""
经典爬楼梯问题,一次爬一级或者两级
"""
def count_stair_ways(n):
"""Returns the number of ways to climb up a flight of
n stairs, moving either 1 step or 2 steps at a time.
>>> count_stair_ways(4)
5
"""
"*** YOUR CODE HERE ***"
def helper(n, step):
if n == 0:
return 1
elif n == 1:
return helper(n - 1, 1)
elif n < 0:
return 0
else:
return helper(n - 1, 1) + helper(n - 2, 2)
return helper(n, 0)
"""
这里的问题区别于之前的count_partition在于,不需要记录每一个step(每一个k的值),因为前面的step值不影响后面的step值,step值都是从1到k任意的,所以需要for i in range(1, k + 1)循环,使n - i从n - 1到n - k
"""
def count_stair_ways(n):
"""Returns the number of ways to climb up a flight of
n stairs, moving either 1 step or 2 steps at a time.
>>> count_stair_ways(4)
5
"""
"*** YOUR CODE HERE ***"
if n == 0:
return 1
elif n == 1:
return 1
elif n < 0:
return 0
else:
return count_stair_ways(n - 1) + count_stair_ways(n - 2)
def count_k(n, k):
""" Counts the number of paths up a flight of n stairs
when taking up to and including k steps at a time.
>>> count_k(3, 3) # 3, 2 + 1, 1 + 2, 1 + 1 + 1
4
>>> count_k(4, 4)
8
>>> count_k(10, 3)
274
>>> count_k(300, 1) # Only one step at a time
1
"""
"*** YOUR CODE HERE ***"
if n == 0:
return 1
elif n < 0:
return 0
else:
total = 0
for i in range(1, k + 1):
total += count_k(n - i, k) #这里不是加count(n - i, i)否则会限制了每一次能跨的步数k
return total
Lecture 10
"""
字符串反转
reverse("word") = drow
reverse("word") = reverse("ord") + "w"
...
reverse("d") = "d"
"""
def reverse_string(str):
if len(str) == 1:
return str
else:
return reverse_string(str[1:]) + str[0]
Lecture 11
"""
Prof强调了在创建对象的时候一定要用constructor,以及在进行computational 函数的构建时
一定要用selector,而不是直接计算,避免violating abstraction barriers
"""
def rational(n, d):
def select(name):
if name == 'n':
return n
elif name == 'd':
return d
return select
def numerator(x):
return x('n') #相当于select('n')
def denumerator(x):
return x('d') #相当于select('d')
def fastest_words(game):
"""Return a list of lists of which words each player typed fastest.
Arguments:
game: a game data abstraction as returned by time_per_word.
>>> p0 = [5, 1, 3]
>>> p1 = [4, 1, 6]
>>> fastest_words(game(['Just', 'have', 'fun'], [p0, p1]))
[['have', 'fun'], ['Just']]
"""
player_indices = range(len(all_times(game))) # contains an *index* for each player
word_indices = range(len(all_words(game))) # contains an *index* for each word
# BEGIN PROBLEM 10
"*** YOUR CODE HERE ***"
"""
对于每个word,检索当前index的所有player中耗时min的player_index,对应的list添加上words_at(index)
"""
fastest_words_list = [[] for _ in player_indices]
times = all_times(game)
for i in word_indices:
min_time_player_index = min(player_indices, key = lambda x: times[x][i]) #这行很重要 意味着将你需要pick的list放入 然后在key中制定lambda函数以制定min的规则
fastest_words_list[min_time_player_index].append(word_at(game, i))
return fastest_words_list
# END PROBLEM 10
Cats
def pawssible_patches(start, goal, limit):
"""A diff function that computes the edit distance from START to GOAL.
This function takes in a string START, a string GOAL, and a number LIMIT.
Arguments:
start: a starting word
goal: a goal word
limit: a number representing an upper bound on the number of edits
>>> big_limit = 10
>>> pawssible_patches("cats", "scat", big_limit) # cats -> scats -> scat
2
>>> pawssible_patches("purng", "purring", big_limit) # purng -> purrng -> purring
2
>>> pawssible_patches("ckiteus", "kittens", big_limit) # ckiteus -> kiteus -> kitteus -> kittens
3
"""
#由于这个函数实际上只在乎次数,不在乎具体将字母换成什么字母,所以只需要判断有多少位被执行了base行为
if limit < 0:
# BEGIN
return 0
# 需要让循环在limit = 0后终止,但这里return 值为多少无所谓 因为通常是在not start or not goal这个判断句下return真实操作值
# 但是不能在limit = 0时终止return 1,因为这里如果limit > 0
# END
if not start or not goal: # 如果两个中只要有一个为空,则需要修改的次数直接为两者之差
# BEGIN
return abs(len(start) - len(goal))
# END
elif start[0] == goal[0]:
return pawssible_patches(start[1:], goal[1:], limit)
else:
# 相当于是每次都虚执行add remove substitute
add = pawssible_patches(start, goal[1:], limit - 1)
# print("DEBUG: add", add)
remove = pawssible_patches(start[1:], goal, limit - 1)
# print("DEBUG:remove", remove)
substitute = pawssible_patches(start[1:], goal[1:], limit - 1)
# print("DEBUG:substitute", substitute)
return min(add, remove, substitute) + 1 #这里+1意思是执行了add remove substitute中三个行为中的一个
# BEGIN
"*** YOUR CODE HERE ***"
# END