Lists
Q1: Factors List
Write
factors_list
, which takes a numbern
and returns a list of its factors in ascending order.
我們可以知道這么一個基本的數學事實: 一個數字的因子最大僅可能為它的一半(當這個數字是偶數的時候). 所以我們的 for
循環只要遍歷到 n // 2 + 1
即可
def factors_list(n):
"""Return a list containing all the numbers that divide `n` evenly, except
for the number itself. Make sure the list is in ascending order.
>>> factors_list(6)
[1, 2, 3]
>>> factors_list(8)
[1, 2, 4]
>>> factors_list(28)
[1, 2, 4, 7, 14]
"""
all_factors = []
# the biggest number which can divide `n` evenly will be `n // 2`
for i in range(1, n // 2 + 1):
if n % i == 0:
all_factors.append(i)
return all_factors
Q2: Flatten
Write a function
flatten
that takes a list and "flattens" it. The list could be a deep list, meaning that there could be a multiple layers of nesting within the list.For example, one use case of
flatten
could be the following:>>> lst = [1, [[2], 3], 4, [5, 6]] >>> flatten(lst) [1, 2, 3, 4, 5, 6]
Make sure your solution does not mutate the input list.
顯然這個問題天然復合遞歸求解的性質, 對於嵌套的 list
, 我們需要遞歸分解它. 那么這又回到了怎么處理遞歸分解的問題:
- 什么是 base case ? 如果是空的
list
就返回[]
- 怎么遞歸分解為更簡單的子問題 ? 也就是我們要如何縮小問題的規模, 我們可以每次嘗試處理嵌套
list
的第一個位置的元素, 根據它們是不是list
可以分解出兩種情況.
最后我們可以寫出如下的代碼:
def flatten(s):
"""Returns a flattened version of list s.
>>> flatten([1, 2, 3]) # normal list
[1, 2, 3]
>>> x = [1, [2, 3], 4] # deep list
>>> flatten(x)
[1, 2, 3, 4]
>>> x # Ensure x is not mutated
[1, [2, 3], 4]
>>> x = [[1, [1, 1]], 1, [1, 1]] # deep list
>>> flatten(x)
[1, 1, 1, 1, 1, 1]
>>> x
[[1, [1, 1]], 1, [1, 1]]
"""
if s == []:
return []
elif type(s[0]) == list:
return flatten(s[0]) + flatten(s[1:])
else:
return s[:1] + flatten(s[1:])
Data Abstraction
Q3: Distance
We will now implement the function
distance
, which computes the distance between two city objects. Recall that the distance between two coordinate pairs(x1, y1)
and(x2, y2)
can be found by calculating thesqrt
of(x1 - x2)**2 + (y1 - y2)**2
. We have already importedsqrt
for your convenience. Use the latitude and longitude of a city as its coordinates; you'll need to use the selectors to access this info!
我們只要分別對傳進來的參數調用 get_lat
和 get_lon
得到值然后計算即可
def distance(city_a, city_b):
"""
>>> city_a = make_city('city_a', 0, 1)
>>> city_b = make_city('city_b', 0, 2)
>>> distance(city_a, city_b)
1.0
>>> city_c = make_city('city_c', 6.5, 12)
>>> city_d = make_city('city_d', 2.5, 15)
>>> distance(city_c, city_d)
5.0
"""
x = (get_lat(city_a) - get_lat(city_b)) ** 2
y = (get_lon(city_a) - get_lon(city_b)) ** 2
return sqrt(x + y)
Q4: Closer city
Next, implement
closer_city
, a function that takes a latitude, longitude, and two cities, and returns the name of the city that is relatively closer to the provided latitude and longitude.You may only use the selectors and constructors introduced above and the
distance
function you just defined for this question.Hint: How can you use your
distance
function to find the distance between the given location and each of the given cities?
根據提示和我們在 Q3 中的 distance
函數, 我們知道我們應該根據 lat
和 lon
建立一個虛擬的城市, 然后使用 distance
函數來計算距離. 這樣才不用寫大量重復的代碼
def closer_city(lat, lon, city_a, city_b):
"""
Returns the name of either city_a or city_b, whichever is closest to
coordinate (lat, lon). If the two cities are the same distance away
from the coordinate, consider city_b to be the closer city.
>>> berkeley = make_city('Berkeley', 37.87, 112.26)
>>> stanford = make_city('Stanford', 34.05, 118.25)
>>> closer_city(38.33, 121.44, berkeley, stanford)
'Stanford'
>>> bucharest = make_city('Bucharest', 44.43, 26.10)
>>> vienna = make_city('Vienna', 48.20, 16.37)
>>> closer_city(41.29, 174.78, bucharest, vienna)
'Bucharest'
"""
tmp = make_city('tmp', lat, lon)
if distance(tmp, city_a) < distance(tmp, city_b):
return get_name(city_a)
else:
return get_name(city_b)
Trees
Q6: Finding Berries!
The squirrels on campus need your help! There are a lot of trees on campus and the squirrels would like to know which ones contain berries. Define the function
berry_finder
, which takes in a tree and returnsTrue
if the tree contains a node with the value'berry'
andFalse
otherwise.Hint: To iterate through each of the branches of a particular tree, you can consider using a
for
loop to get each branch.
這是一道很經典的樹的遞歸題目. 我們要在所有的節點中找到 label 為 berry
的點, 用遞歸的思路如下:
- 什么是 base case ? 顯然為葉子結點的時候是 base case, 這個時候我們看它的 label 是不是
- 怎么分解為更簡單的子問題 ? 容易想到, 我們只要有任何一個分支的某個節點存在
berry
即可, 或者說我們當前分支的 label 為berry
.
def berry_finder(t):
"""Returns True if t contains a node with the value 'berry' and
False otherwise.
>>> scrat = tree('berry')
>>> berry_finder(scrat)
True
>>> sproul = tree('roots', [tree('branch1', [tree('leaf'), tree('berry')]), tree('branch2')])
>>> berry_finder(sproul)
True
>>> numbers = tree(1, [tree(2), tree(3, [tree(4), tree(5)]), tree(6, [tree(7)])])
>>> berry_finder(numbers)
False
>>> t = tree(1, [tree('berry',[tree('not berry')])])
>>> berry_finder(t)
True
"""
if is_leaf(t):
return label(t) == 'berry'
return any([berry_finder(b) for b in branches(t)]) or label(t) == 'berry'
Q7: Sprout leaves
Define a function
sprout_leaves
that takes in a tree,t
, and a list of leaves,leaves
. It produces a new tree that is identical tot
, but where each old leaf node has new branches, one for each leaf inleaves
.For example, say we have the tree
t = tree(1, [tree(2), tree(3, [tree(4)])])
:1 / \ 2 3 | 4
If we call
sprout_leaves(t, [5, 6])
, the result is the following tree:1 / \ 2 3 / \ | 5 6 4 / \ 5 6
這同樣是要用遞歸解決的題目, 顯然 base case 就是葉子結點, 當我們遇到葉子結點的時候要把 leaves
添加上去. 如果是分支, 那么我們就要檢查它的每一個子樹.
def sprout_leaves(t, leaves): """Sprout new leaves containing the data in leaves at each leaf in the original tree t and return the resulting tree. >>> t1 = tree(1, [tree(2), tree(3)]) >>> print_tree(t1) 1 2 3 >>> new1 = sprout_leaves(t1, [4, 5]) >>> print_tree(new1) 1 2 4 5 3 4 5 >>> t2 = tree(1, [tree(2, [tree(3)])]) >>> print_tree(t2) 1 2 3 >>> new2 = sprout_leaves(t2, [6, 1, 2]) >>> print_tree(new2) 1 2 3 6 1 2 """ if is_leaf(t): return tree(label(t), [tree(leaf) for leaf in leaves]) return tree(label(t), [sprout_leaves(b, leaves) for b in branches(t)])