Lab 8 : Permutations and Combinations¶
0 Preliminaries¶
To run doctests, add the following to the bottom of your file:
if (__name__ == '__main__'):
import doctest
doctest.testmod(optionflags= doctest.NORMALIZE_WHITESPACE)
1 Counting permutations and combinations¶
Exercise 1 Write a function which computes factorial. Use a for
or while
loop.
def fact(n):
"""
>>> fact(0)
1
>>> fact(1)
1
>>> fact(5)
120
"""
Exercise 2 Write a function which computes factorial. This time do not use a loop. Rather, define fact_rec
so that it calls itself on a “smaller” input.
def fact_rec(n):
"""
>>> fact_rec(0)
1
>>> fact_rec(1)
1
>>> fact_rec(5)
120
"""
Exercise 3 Write a function which counts how many permutations of length r
there are in a collection of n
elements. Use fact
or fact_rec
.
def perm(n, r):
"""
>>> perm(4, 0)
1
>>> perm(4, 1)
4
>>> perm(4, 2)
12
>>> perm(4, 3)
24
"""
Exercise 4 Write a function which counts how many combinations of length r
there are in a collection of n
elements. Use perm
and either fact
or fact_rec
.
def comb(n, r):
"""
>>> comb(3,0)
1
>>> comb(3,1)
3
>>> comb(3,2)
3
>>> comb(3,3)
1
"""
2 Listing combinations¶
Exercise 5 Write a function which takes an element x
and a list of lists lol
and inserts x
at the beginning of every list in lol
.
def insert_first(x, lol):
"""
>>> insert_first(1, [[2, 3], [2, 4], [3, 4]])
[[1, 2, 3], [1, 2, 4], [1, 3, 4]]
"""
Exercise 6 Write a function which takes a list of elements l
and lists out all the combinations of elements of l
of size r
.
Here is one way to approach this problem. We will define list_comb
so that it calls itself (twice). First we want to explicitly handle the following cases: when r
is 0, when l
is empty and when r
is 1. Then for larger l
and r
we will call list_comb
on “smaller” inputs. Consider this example:
>>> list_comb([1, 2, 3, 4], 2)
[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
We can think of the desired output as two lists appended together:
[[1, 2], [1, 3], [1, 4]]
and
[[2, 3], [2, 4], [3, 4]]
Think about how you might produce each of these two lists using list_comb
(assuming that it does what it is supposed to do).
- Producing the first list requires a helper function: we start by calling
list_comb
on[2, 3, 4]
and 1, which gives[[2], [3], [4]]
; and then we applyinsert_first
to 1 and the result,[[2], [3], [4]]
. - Producing the second list is straightforward: we call
list_comb
on[2, 3, 4]
and 2. - The final step is to append the results from steps 1 and 2 together.
def list_comb(l, r):
"""
>>> list_comb([], 0)
[[]]
>>> list_comb([], 1)
[]
>>> list_comb([1, 2, 3, 4], 0)
[[]]
>>> list_comb([1, 2, 3, 4], 1)
[[1], [2], [3], [4]]
>>> list_comb([1, 2, 3, 4], 2)
[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
>>> list_comb([1, 2, 3, 4], 3)
[[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]
>>> list_comb([1, 2, 3, 4], 4)
[[1, 2, 3, 4]]
"""
3 Listing permutations¶
Exercise 7 Write a function which takes a list of lists and appends all of them together.
def append_lists(lol):
"""
>>> append_lists([[1, 2, 3], [4, 5], [6]])
[1, 2, 3, 4, 5, 6]
>>> append_lists([])
[]
>>> append_lists([[]])
[]
"""
Exercise 8 Write a function which takes an element x
and a list l
and returns a list of lists containing all of the possible ways of inserting x
into l
.
def insert_all(x, l):
"""
>>> insert_all(1, [2, 3, 4])
[[1, 2, 3, 4], [2, 1, 3, 4], [2, 3, 1, 4], [2, 3, 4, 1]]
>>> insert_all(1, [])
[[1]]
"""
Exercise 9 Write a function which takes an element x
and a list of lists lol
and returns a list of lists containing all of the possible ways of inserting x
into a list in lol
. Use append_lists
and insert_all
. (Hint: first apply insert_all
to every element in lol
; and then apply append_lists
to the result.)
def insert_all_lists(x, lol):
"""
>>> insert_all_lists(1, [[2, 3], [2, 4]])
[[1, 2, 3], [2, 1, 3], [2, 3, 1], [1, 2, 4], [2, 1, 4], [2, 4, 1]]
"""
Exercise 10 Write a function which takes a list of elements l
and lists out all the permutations of elements of l
of size r
. Use insert_all_lists
. (Hint: the solution for list_comb
can be adapted almost verbatim.)
def list_perm(l, r):
"""
>>> list_perm([], 0)
[[]]
>>> list_perm([], 1)
[]
>>> list_perm([7, 8, 9], 0)
[[]]
>>> list_perm([7, 8, 9], 1)
[[7], [8], [9]]
>>> list_perm([7, 8, 9], 2)
[[7, 8], [8, 7], [7, 9], [9, 7], [8, 9], [9, 8]]
>>> list_perm([7, 8, 9], 3)
[[7, 8, 9], [8, 7, 9], [8, 9, 7], [7, 9, 8], [9, 7, 8], [9, 8, 7]]
"""