Lab05 题解 (UCB CS61A@2021 Fall)


Write factors_list, which takes a number n and returns a list of its factors in ascending order.

我们可以知道这么一个基本的数学事实: 一个数字的因子最大仅可能为它的一半(当这个数字是偶数的时候). 所以我们的 for 循环只要遍历到 n // 2 + 1 即可

python

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

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:

text

>>> 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, 我们需要递归分解它. 那么这又回到了怎么处理递归分解的问题:

  1. 什么是 base case ? 如果是空的 list 就返回 []
  2. 怎么递归分解为更简单的子问题 ? 也就是我们要如何缩小问题的规模, 我们可以每次尝试处理嵌套 list 的第一个位置的元素, 根据它们是不是 list 可以分解出两种情况.

最后我们可以写出如下的代码:

python

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:])

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 the sqrt of (x1 - x2)**2 + (y1 - y2)**2. We have already imported sqrt 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_latget_lon 得到值然后计算即可

python

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)

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 函数, 我们知道我们应该根据 latlon 建立一个虚拟的城市, 然后使用 distance 函数来计算距离. 这样才不用写大量重复的代码

python

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)

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 returns True if the tree contains a node with the value 'berry' and False 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 的点, 用递归的思路如下:

  1. 什么是 base case ? 显然为叶子结点的时候是 base case, 这个时候我们看它的 label 是不是
  2. 怎么分解为更简单的子问题 ? 容易想到, 我们只要有任何一个分支的某个节点存在 berry 即可, 或者说我们当前分支的 label 为 berry.

python

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'

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 to t, but where each old leaf node has new branches, one for each leaf in leaves.

For example, say we have the tree t = tree(1, [tree(2), tree(3, [tree(4)])]):

text

 1
/ \
2   3
   |
   4

If we call sprout_leaves(t, [5, 6]), the result is the following tree:

text

      1
    /   \
   2     3
  / \    |
 5   6   4
        / \
       5   6

这同样是要用递归解决的题目, 显然 base case 就是叶子结点, 当我们遇到叶子结点的时候要把 leaves 添加上去. 如果是分支, 那么我们就要检查它的每一个子树.

python

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)])