Homework 3: Higher-Order Functions, Self Reference, Recursion, Tree Recursion

Q1: Compose

编写一个高阶函数composer,它返回两个函数funcfunc_adder。 func是一个单参数函数,它应用到目前为止已经组合的所有函数。这些函数将首先应用最新的函数(参见doctests和示例)。 func_adder用于向我们的组合添加更多函数,当调用另一个函数g时,func_adder应该返回一个新的func和一个新的func_adder

如果没有参数传入composer,则返回的func是恒等函数。

举例来说:

>>> add_one = lambda x: x + 1
>>> square = lambda x: x * x
>>> times_two = lambda x: x + x

>>> f1, func_adder = composer()
>>> f1(1)
1

>>> f2, func_adder = func_adder(add_one)
>>> f2(1)
2   # 1 + 1

>>> f3, func_adder = func_adder(square)
>>> f3(3)
10  # 1 + (3**2)

>>> f4, func_adder = func_adder(times_two)
>>> f4(3)
37  # 1 + ((2 * 3) **2)

提示:你的func_adder应该返回两个参数func和 func_adder.

我们知道什么函数返回funcfunc_adder

(这个提示真的神来之笔:由于compose返回

func

func_adder这两个函数

所以func_adder应该是以新func为形参的compose函数

(func    =         lambda x:func(g(x))       

g(x)作为原函数的参数x        逐级嵌套 )如图:

Homework 3: Higher-Order Functions, Self Reference, Recursion, Tree Recursion_第1张图片

def composer(func=lambda x: x):
    """
    Returns two functions -
    one holding the composed function so far, and another
    that can create further composed problems.
    >>> add_one = lambda x: x + 1
    >>> mul_two = lambda x: x * 2
    >>> f, func_adder = composer()
    >>> f1, func_adder = func_adder(add_one)
    >>> f1(3)
    4
    >>> f2, func_adder = func_adder(mul_two)
    >>> f2(3) # should be 1 + (2*3) = 7
    7
    >>> f3, func_adder = func_adder(add_one)
    >>> f3(3) # should be 1 + (2 * (3 + 1)) = 9
    9
    """
    def func_adder(g):
        "*** YOUR CODE HERE ***"
        return  composer(lambda x:func(g(x)))

    return func, func_adder

pass:

PS D:\pycharm\python document\CS61A class homework\hw03> python3 ok -q composer
=====================================================================
Assignment: Homework 3
OK, version v1.18.1
=====================================================================

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Running tests

---------------------------------------------------------------------
Test summary
    1 test cases passed! No cases failed.

Q4: Count change

Once the machines take over, the denomination of every coin will be a power of two: 1-cent, 2-cent, 4-cent, 8-cent, 16-cent, etc. There will be no limit to how much a coin can be worth.

Given a positive integer total, a set of coins makes change for total if the sum of the values of the coins is total. For example, the following sets make change for 7:

  • 7 1-cent coins
  • 5 1-cent, 1 2-cent coins
  • 3 1-cent, 2 2-cent coins
  • 3 1-cent, 1 4-cent coins
  • 1 1-cent, 3 2-cent coins
  • 1 1-cent, 1 2-cent, 1 4-cent coins

Thus, there are 6 ways to make change for 7. Write a recursive function count_change that takes a positive integer total and returns the number of ways to make change for total using these coins of the future.

Hint: Refer the implementation of count_partitions for an example of how to count the ways to sum up to a total with smaller parts. If you need to keep track of more than one value across recursive calls, consider writing a helper function.

分析:作者把此题核心分为两个函数

divide函数:

作用:

求 对于total 满足1------小于total的最大2的倍数 面值美分  的排列种类

核心:

将一种情况分为两种情况即:

当前有最大数的排列数量        和        无当前最大数的数量

举个例子如图(函数实现过程):

Homework 3: Higher-Order Functions, Self Reference, Recursion, Tree Recursion_第2张图片

max1:

求的是 小于total的最大2的倍数

def divide(total,num):
    if num==1:
        return 1
    if total0:
        return max1(total//2)*2
def count_change(total):
    """Return the number of ways to make change for total.

    >>> count_change(7)
    6
    >>> count_change(10)
    14
    >>> count_change(20)
    60
    >>> count_change(100)
    9828
    >>> from construct_check import check
    >>> # ban iteration
    >>> check(HW_SOURCE_FILE, 'count_change', ['While', 'For'])
    True
    """
    "*** YOUR CODE HERE ***"
    if total==1:
        return 1
    return divide(total,max1(total))

pass结果:

PS D:\pycharm\python document\CS61A class homework\hw03> python3 ok -q count_change
=====================================================================
Assignment: Homework 3
OK, version v1.18.1
=====================================================================

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Running tests

---------------------------------------------------------------------
Test summary
    1 test cases passed! No cases failed.

Q5: Towers of Hanoi

一个经典的难题称为塔的河内是一个游戏,包括三个 杆和许多不同尺寸的圆盘,圆盘可以在任何杆上滑动。 这个谜题从n磁盘开始,磁盘按照大小的升序整齐地堆叠在一起, start棒,顶部最小,形成圆锥形。

拼图的目的是将整个堆叠移动到end杆, 遵守以下规则:

  • 一次只能移动一个磁盘。
  • 每次移动包括从其中一根杆上取下顶部(最小)的圆盘, 把它滑到另一个杆上,在其他可能已经被 存在于该杆上。
  • 不能将磁盘放在较小磁盘的顶部。

完成move_stack的定义,它将打印出执行以下操作所需的步骤: 将n盘从start棒移动到end棒,不违反 规则提供的print_move函数将打印出移动 从给定的origin到给定的destination的单个磁盘。

提示:在一张纸上画出几个带有各种n的游戏,并尝试 找到一个适用于任何n的磁盘运动模式。在你的解决方案中, 当你需要移动任何数量的 小于n的圆盘从一个棒到另一个棒。如果你需要更多帮助, 以下提示。

 分析:

核心:拆分思想(动态规划dp)

对于n个盘子需要从起点到终点的问题可以转化为

1.将n个盘子需要从起点到非起点或终点,

2.第n个盘子从起点到终点

3.再将n-1盘子放到终点的过程

(1)其中对于n==2的情况(即递归终点)需要模拟出相应过程

注意:n==1需要额外说明

如图所示:

Homework 3: Higher-Order Functions, Self Reference, Recursion, Tree Recursion_第3张图片

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 ***"
    n_s=0
    if 1!=start and 1!=end:
        n_s=1
    if 2!=start and 2!=end:
        n_s=2
    if 3!=start and 3!=end:
        n_s=3
    if n==1:
        print_move(start,end)
        return
    if n==2:
        print_move(start,n_s)
        print_move(start,end)
        print_move(n_s,end)
        return
    move_stack(n-1,start,n_s)
    print_move(start,end)
    move_stack(n-1,n_s,end)

pass情况:

PS D:\pycharm\python document\CS61A class homework\hw03> python3 ok -q move_stack
=====================================================================
Assignment: Homework 3
OK, version v1.18.1
=====================================================================

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Running tests

---------------------------------------------------------------------
Test summary
    1 test cases passed! No cases failed.

Q6: Anonymous factorial

The recursive factorial function can be written as a single expression by using a conditional expression.

>>> fact = lambda n: 1 if n == 1 else mul(n, fact(sub(n, 1)))
>>> fact(5)
120

However, this implementation relies on the fact (no pun intended) that fact has a name, to which we refer in the body of fact. To write a recursive function, we have always given it a name using a def or assignment statement so that we can refer to the function within its own body. In this question, your job is to define fact recursively without giving it a name!

Write an expression that computes n factorial using only call expressions, conditional expressions, and lambda expressions (no assignment or def statements). Note in particular that you are not allowed to use make_anonymous_factorial in your return expression. The sub and mul functions from the operator module are the only built-in functions required to solve this problem:

from operator import sub, mul

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
    """
    return lambda n : (lambda x, function : 1 if x == 1 else x * function(x - 1, function))(n, lambda x, function : 1 if x == 1 else x * function(x - 1, function))

分析:

 from operator import sub, mul
 ​
 def make_anonymous_factorial():
     def function(x, function):
         if(x == 1):
             return 1
         else:
             return function(x - 1, function) * x
     return lambda n : function(n, function)

 我采取了High-order Function的方法,

定义一个将自身作为参数的函数

从更深层次的角度来讲,

这不过是将“函数”的Abstraction程度降低了一层,将 “函数寻址”这一行为显式地实现了

function()用lambda表达出来即:

lambda x, function : 1 if x == 1 else x * function(x - 1, function)

合并即以下答案:

1.lambda x:

函数体:

( lambda x,function:function(x-1,function)*x if x>0 else 1)

参数:

(x,lambda x,function:function(x-1,function)*x if x>0 else 1)

另外一种形式:

2.

lambda x:

函数体:

(lambda x,function:function(x-1,function)*x if x>0 else 1)

参数:

(x-1,lambda x,function:function(x-1,function)*x if x>0 else 1)

*x if x>0 else 1

错误分析

function(未给出定义)

 1.error:

(lambda x,function:function(x-1,function)*x if x>0 else 1)

(x-1,function)*x if x>0 else 1

2.error:

(lambda x,function:function(x-1,function)*x if x>0 else 1)

(x,function)

pass情况:

PS D:\pycharm\python document\CS61A class homework\hw03> python3 ok -q make_anonymous_factorial
=====================================================================
Assignment: Homework 3
OK, version v1.18.1
=====================================================================

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Running tests

---------------------------------------------------------------------
Test summary
    1 test cases passed! No cases failed.

Backup... 100% complete
Backup past deadline by 1245 days, 3 hours, 43 minutes, and 25 seconds


OK is up to date

 完整答案:

HW_SOURCE_FILE=__file__


def composer(func=lambda x: x):
    """
    Returns two functions -
    one holding the composed function so far, and another
    that can create further composed problems.
    >>> add_one = lambda x: x + 1
    >>> mul_two = lambda x: x * 2
    >>> f, func_adder = composer()
    >>> f1, func_adder = func_adder(add_one)
    >>> f1(3)
    4
    >>> f2, func_adder = func_adder(mul_two)
    >>> f2(3) # should be 1 + (2*3) = 7
    7
    >>> f3, func_adder = func_adder(add_one)
    >>> f3(3) # should be 1 + (2 * (3 + 1)) = 9
    9
    """
    def func_adder(g):
        "*** YOUR CODE HERE ***"
        return  composer(lambda x:func(g(x)))

    return func, func_adder


def g(n):
    """Return the value of G(n), computed recursively.

    >>> g(1)
    1
    >>> g(2)
    2
    >>> g(3)
    3
    >>> g(4)
    10
    >>> g(5)
    22
    >>> from construct_check import check
    >>> # ban iteration
    >>> check(HW_SOURCE_FILE, 'g', ['While', 'For'])
    True
    """
    "*** YOUR CODE HERE ***"
    if n<=3:
        return n
    else:
        return g(n-1)+2*g(n-2)+3*g(n-3)


def g_iter(n):
    """Return the value of G(n), computed iteratively.

    >>> g_iter(1)
    1
    >>> g_iter(2)
    2
    >>> g_iter(3)
    3
    >>> g_iter(4)
    10
    >>> g_iter(5)
    22
    >>> from construct_check import check
    >>> # ban recursion
    >>> check(HW_SOURCE_FILE, 'g_iter', ['Recursion'])
    True
    """
    "*** YOUR CODE HERE ***"
    if n<=3:
        return n
    else:
        f1=1
        f2=2
        f3=3
        f4=3*f1+2*f2+f3
        while n>4:
            f1=f2
            f2=f3
            f3=f4
            f4=3*f1+2*f2+f3
            n-=1
        return f4




def missing_digits(n):
    """Given a number a that is in sorted, increasing order,
    return the number of missing digits in n. A missing digit is
    a number between the first and last digit of a that is not in n.
    >>> missing_digits(1248) # 3, 5, 6, 7
    4
    >>> missing_digits(1122) # No missing numbers
    0
    >>> missing_digits(123456) # No missing numbers
    0
    >>> missing_digits(3558) # 4, 6, 7
    3
    >>> missing_digits(35578) # 4, 6
    2
    >>> missing_digits(12456) # 3
    1
    >>> missing_digits(16789) # 2, 3, 4, 5
    4
    >>> missing_digits(19) # 2, 3, 4, 5, 6, 7, 8
    7
    >>> missing_digits(4) # No missing numbers between 4 and 4
    0
    >>> from construct_check import check
    >>> # ban while or for loops
    >>> check(HW_SOURCE_FILE, 'missing_digits', ['While', 'For'])
    True
    """
    "*** YOUR CODE HERE ***"
    if n//10==0:
        return 0
    last=n%10
    n=n//10
    if n%100:
        return max1(total//2)*2
def count_change(total):
    """Return the number of ways to make change for total.

    >>> count_change(7)
    6
    >>> count_change(10)
    14
    >>> count_change(20)
    60
    >>> count_change(100)
    9828
    >>> from construct_check import check
    >>> # ban iteration
    >>> check(HW_SOURCE_FILE, 'count_change', ['While', 'For'])
    True
    """
    "*** YOUR CODE HERE ***"
    if total==1:
        return 1
    return divide(total,max1(total))


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 ***"
    n_s=0
    if 1!=start and 1!=end:
        n_s=1
    if 2!=start and 2!=end:
        n_s=2
    if 3!=start and 3!=end:
        n_s=3
    if n==1:
        print_move(start,end)
        return
    if n==2:
        print_move(start,n_s)
        print_move(start,end)
        print_move(n_s,end)
        return
    move_stack(n-1,start,n_s)
    print_move(start,end)
    move_stack(n-1,n_s,end)


from operator import sub, mul

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
    """
    return lambda x:(lambda x,function:function(x-1,function)*x if x>0 else 1)(x-1,lambda x,function:function(x-1,function)*x if x>0 else 1)*x if x>0 else 1

你可能感兴趣的:(CS61A,python,开发语言)