Homework 2: Recursion
Due by 11:59pm on Thursday, September 24
查看汉语翻译
Instructions
Download hw02.zip. Inside the archive, you will find a file called
hw02.py, along with a copy of the ok
autograder.
Submission: When you are done, submit with python3 ok
--submit
. You may submit more than once before the deadline; only the
final submission will be scored. Check that you have successfully submitted
your code on okpy.org. See Lab
0 for more instructions on
submitting assignments.
Using Ok: If you have any questions about using Ok, please refer to this guide.
Readings: You might find the following references useful:
Grading: Homework is graded based on correctness. Each incorrect problem will decrease the total score by one point. There is a homework recovery policy as stated in the syllabus. This homework is out of 2 points.
Required questions
Q1: Num eights
Write a recursive function num_eights
that takes a positive integer x
and
returns the number of times the digit 8 appears in x
.
Use recursion - the tests will fail if you use any assignment statements.
def num_eights(x):
"""Returns the number of times 8 appears as a digit of x.
>>> num_eights(3)
0
>>> num_eights(8)
1
>>> num_eights(88888888)
8
>>> num_eights(2638)
1
>>> num_eights(86380)
2
>>> num_eights(12345)
0
>>> from construct_check import check
>>> # ban all assignment statements
>>> check(HW_SOURCE_FILE, 'num_eights',
... ['Assign', 'AugAssign'])
True
"""
"*** YOUR CODE HERE ***"
Watch the hints video below for somewhere to start:
Use Ok to test your code:
python3 ok -q num_eights
Q2: Ping-pong
The ping-pong sequence counts up starting from 1 and is always either counting
up or counting down. At element k
, the direction switches if k
is a
multiple of 8 or contains the digit 8. The first 30 elements of the ping-pong
sequence are listed below, with direction swaps marked using brackets at the
8th, 16th, 18th, 24th, and 28th elements:
Index | 1 | 2 | 3 | 4 | 5 | 6 | 7 | [8] | 9 | 10 | 11 | 12 | 13 | 14 | 15 | [16] | 17 | [18] | 19 | 20 | 21 | 22 | 23 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
PingPong Value | 1 | 2 | 3 | 4 | 5 | 6 | 7 | [8] | 7 | 6 | 5 | 4 | 3 | 2 | 1 | [0] | 1 | [2] | 1 | 0 | -1 | -2 | -3 |
Index (cont.) | [24] | 25 | 26 | 27 | [28] | 29 | 30 |
---|---|---|---|---|---|---|---|
PingPong Value | [-4] | -3 | -2 | -1 | [0] | -1 | -2 |
Implement a function pingpong
that returns the nth element of the ping-pong
sequence without using any assignment statements.
You may use the function num_eights
, which you defined in the previous question.
Use recursion - the tests will fail if you use any assignment statements.
Hint: If you're stuck, first try implementing
pingpong
using assignment statements and awhile
statement. Then, to convert this into a recursive solution, write a helper function that has a parameter for each variable that changes values in the body of the while loop.
def pingpong(n):
"""Return the nth element of the ping-pong sequence.
>>> pingpong(8)
8
>>> pingpong(10)
6
>>> pingpong(15)
1
>>> pingpong(21)
-1
>>> pingpong(22)
-2
>>> pingpong(30)
-2
>>> pingpong(68)
0
>>> pingpong(69)
-1
>>> pingpong(80)
0
>>> pingpong(81)
1
>>> pingpong(82)
0
>>> pingpong(100)
-6
>>> from construct_check import check
>>> # ban assignment statements
>>> check(HW_SOURCE_FILE, 'pingpong', ['Assign', 'AugAssign'])
True
"""
"*** YOUR CODE HERE ***"
Watch the hints video below for somewhere to start:
Use Ok to test your code:
python3 ok -q pingpong
Q3: Missing Digits
Write the recursive function missing_digits
that takes a number n
that is sorted in
increasing order (for example, 12289
is valid but 15362
and 98764
are
not). It returns the number of missing digits in n
. A missing digit is a number between the first
and last digit of n
of a that is not in n
.
Use recursion - the tests will fail if you use while or for loops.
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 ***"
Watch the hints video below for somewhere to start:
Use Ok to test your code:
python3 ok -q missing_digits
Q4: Count coins
Given a positive integer total
, a set of coins makes change for total
if
the sum of the values of the coins is total
. Here we will use standard US Coin values: 1, 5, 10,
25 For example, the following
sets make change for 15
:
- 15 1-cent coins
- 10 1-cent, 1 5-cent coins
- 5 1-cent, 2 5-cent coins
- 5 1-cent, 1 10-cent coins
- 3 5-cent coins
- 1 5-cent, 1 10-cent coin
Thus, there are 6 ways to make change for 15
. Write a recursive function
count_coins
that takes a positive integer total
and returns the number of
ways to make change for total
using coins. Use the next_largest_coin
function given
to you to calculate the next largest coin denomination given your current coin. I.e.
next_largest_coin(5)
= 10
.
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.
def next_largest_coin(coin):
"""Return the next coin.
>>> next_largest_coin(1)
5
>>> next_largest_coin(5)
10
>>> next_largest_coin(10)
25
>>> next_largest_coin(2) # Other values return None
"""
if coin == 1:
return 5
elif coin == 5:
return 10
elif coin == 10:
return 25
def count_coins(total):
"""Return the number of ways to make change for total 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 ***"
Watch the hints video below for somewhere to start:
Use Ok to test your code:
python3 ok -q count_coins
Submit
Make sure to submit this assignment by running:
python3 ok --submit
Just for Fun Questions
This question demonstrates that it's possible to write recursive functions without assigning them a name in the global frame.
Q5: 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 'YOUR_EXPRESSION_HERE'
Use Ok to test your code:
python3 ok -q make_anonymous_factorial