LMU | CMSI 281
DATA STRUCTURES AND ALGORITHMS I
Practice Questions
  1. Simple Classes
    1. Give a UML class diagram for a part of a movie search application that keeps tracks of movies, actors, characters, directors, producers, release dates, songs (and their authors), and writers. You need only show the classes and their relationships (with cardinalities), though throwing in a few fields cannot hurt.
    2. Give a UML class diagram for a part of an HR database that keeps track of employees and their managers (who are also employees), the departments they work in, and the projects they work on. Employees have a name, birthday, salary, and zero or one mananger. Employees can belong to one or two departments and can work on any number of projects, including zero. Projects have a budget and are run by a single department. In your diagram, show fields but not operations, and show all cardinalities. Pay attention to generalization, composition and aggregation.
    3. Draw a UML class diagram for basketball teams, their players (and their positions), their coaches, their schedules and their win-loss records.
    4. Assume someone has already written an immutable Ellipse class, with all fields private, a constructor taking in both radii, and public methods to get the radii, the circumference, and the area, and a toString method. Write an immutable class called Circle that extends the ellipse class (to leverage all the hard work that the ellipse class does) but still feels like a circle for users of the new circle class.
    5. Assume someone has already written an immutable Ellipse class, with all fields private, a constructor taking in both radii, and public methods to get the radii, the circumference, and the area. Write an immutable class called Cylinder that relies on the ellipse class to help it get its surface area and volume.
    6. Write a Java interface for a robotic arm that controls an adjustable wrench. Be creative but not too unrealistic. You may assume the existence of classes named Point and Vector for 3-D positions and directions, respectively.
    7. Write a Java interface for a robotic arm that controls a flame thrower. Be creative but not too unrealistic. You may assume the existence of classes named Point and Vector for 3-D positions and directions, respectively.
    8. Write a Java interface for a sequence with the following behavior. At any time the sequence is in either read-only or write-only mode. The sequence must be opened before it can be used, and must be closed before it can be reopened again. The mode (read only or write only) can only be set when the sequence is opened. Reading is always done sequentially from the beginning of the sequence; there is no random access nor is there any backing up. Writing can only be done by adding new elements to the end of the sequence; there is no overwriting of elements. However the sequence can be completely erased. The sequence can, but does not have to be, constructed with a fixed capacity, so writing may cause an exception to be thrown if the sequence is full (though note that this is not the only possible exception that can be thrown).
  2. Simple Functions
    1. Write a function to convert all characters in a string to uppercase.
    2. Write a recursive function that takes in an integer n and returns the largest integer less than or equal to log2n.
    3. Write a recursive function that takes in an integer n and returns the largest integer less than or equal to log3n.
    4. Write a recursive function to return the number of digits in a natural number. Actually write the function recursively; don't use any shortcuts like Integer.toString(n).length()
    5. Write a function that takes in an integer n and returns whether the string that denotes the base 10 value of n is a palindrome. For example, the function would return true for the arguments 2992, 3, and 32023, but false for 104 and 31133.
    6. Write a console-based application to average its command line arguments, or to prompt the user for a file name containing numbers to average if no command line arguments are given.
    7. Addition is defined by repeating the "increment" operation, multiplication by repeating addition, exponentiation by repeating multiplication, and so on. Write a Java or C# method for the next "operator" in this sequence.
    8. Write a recursive method to compute xn, where x is a BigInteger and n is an integer. Your algorithm should take about log n "steps", not n-1 steps.
    9. Consider the following method, which displays all possible strings of a given length from a given alphabet to standard output.
      public static void showStrings(char[] alphabet, int length) {
          show("", alphabet, length);
      }
      
      For example, the call showStrings(new char[]{'a', 'b', 'c'}, 2) displays:
          aa
          ab
          ac
          ba
          bb
          bc
          ca
          cb
          cc
      
      Write the helper method show recursively.
    10. Write a method which takes in a string, which is the name of a file, and a character, and returns the number of occurrences of that character in the file. Make sure to handle all errors — for example, if the file was opened, then it had better get closed before your method returns (for whatever reason).
  3. Complexity
    1. What is the time complexity of this code fragment? (Use Θ-notation)

      int x = 1;
      for (int i = 0; i < n; i++) {
          for (int j = 1; j <= x; j++) {
              System.out.println("*");
          }
          x = x + x;
      }
      
    2. What is the time complexity of this code fragment? (Use Θ-notation)

      for (int i = 0; i < n; i++) {
          for (int j = 0; j < i; i *= 2) {
              System.out.println("*");
          }
      }
      
    3. What is the time complexity of this code fragment? (Use Θ-notation)

      for (int i = 1; i * i <= n; i++) {
          for (int j = 1; j <= n; j += j) {
              System.out.println("*");
          }
      }
      
    4. What is the time complexity of this code fragment? (Use Θ-notation)

      for (int i = 1; i <= n; i *= 2)
          for (int j = 1; j <= n; j++)
              System.out.println("*");
          }
      }
      
    5. What is the time complexity of this code fragment? (Use Θ-notation)

      for (int i = 1; i <= n; i *= 2)
          for (int j = 1; j <= i; j++)
              System.out.println("*");
          }
      }
      
    6. What is the time complexity of this code fragment? (Use Θ-notation)

      for (int i = 1; i <= n * n; i++) {
          for (int j = 1; j <= n; j *= 2) {
              System.out.println("*");
          }
      }
      
    7. What is the time complexity of this code fragment? (Use Θ-notation)

      for (int i = 1; i <= n; i++) {
          for (int j = 1; j <= i * i; j *= 2) {
              System.out.println("*");
          }
      }
      
    8. What is the time complexity of this code fragment? (Use Θ-notation)

      for (int i = 1; i <= n; i++) {
          for (int j = 1; j <= i; j *= 2) {
              System.out.println("*");
          }
      }
      
    9. What is the time complexity of this code fragment? (Use Θ-notation)

      for (int i = n; n >= 1; n /= 4) {
          for (int j = 0; j < i; j++) {
              System.out.println("*");
          }
      }
      
    10. Give both the best-case and worst-case time complexities of this code fragment. (Use Θ-notation)

      // Assume some global variable t is defined out here
      for (int i = n; n >= 1; n /= 2) {
          if (new Date().getTime() > t) {
              for (int j = 0; j < i; j++) {
                  System.out.print("*");
              }
          }
      }
      
    11. Give both the best-case and worst-case time complexities of this function. (Use Θ-notation)

          public static long power(int x, int n) {
              return n == 0 ? 1
                  : n % 2 == 0 ? power(x * x, n / 2)
                  : x * power(x * x, n / 2)
          }
      
    12. What is the time complexity (in Θ-notation) of a procedure to print out the exact value of 2n, where n is a nonnegative integer? The procedure described is supposed to print a result no matter how large the result may be.
    13. An algorithm with time complexity T(n) = n3 can process a 100-element list on our PC in 10 seconds.
      1. How long would it take to process a 200-element list?
      2. If we ran the algorithm on a machine that was 10 times faster than our PC, how large of a list could we process in 30 seconds?
      3. How much faster than our PC would a computer have to be in order to process a 1000000000-element list in a time span of 1 hour?
    14. An algorithm with complexity function T(n) = n log n processes a 64-element list in three minutes and 12 seconds on our PC.
      1. How long does it take to process a 128-element list?
      2. How large of a list could a computer that is 8 times faster than our PC process in 10 seconds?
      3. How much faster would a computer have to be than our PC to process a list of size 10 in a second?
    15. An algorithm of with time complexity function T, where T(n) = 2n log n, can process a 32 element list in 2 minutes and 40 seconds on our PC.
      1. How long would it take to process a 64 element list?
      2. If we ran the algorithm on a machine that was 4 times faster than our PC, how large of a list could we process in 16 seconds?
    16. An algorithm with complexity function T(n) = n2 processes a 100-element list in two minutes on our PC.
      1. How long does it take to process a 200-element list?
      2. How large of a list could a computer that is 2500 times faster than our PC process in a minute?
      3. How much faster would a computer have to be than our PC to process an element of size one billion in a second?
    17. An algorithm with complexity function T(n) = 2n can process a 50-node graph on our PC in one month.
      1. How long would it take to process a 75-node graph?
      2. If we ran the algorithm on a machine that was one billion times faster than our PC, how large of a graph could we process in one month?
      3. Using the computer in Part (b) above, could we process a 100-element graph in our lifetime? Why or why not?
    18. We have seen that there is little hope of solving problems of size 100 or so with algorithms of complexity Θ(2n) even when billions of operations can be carried out per second. But what about algorithms of complexity Θ(1.1n)? How do these algorithms compete with quadratic algorithms? In particular, if a billion operations can be performed in one second, up to what problem size will the Θ(1.1n) be faster than a Θ(n2) algorithm?
    19. Give an example of an algorithm with worst-case complexity Θ(n3/2).
    20. Consider the three complexity classes Θ(log2n), Θ(ln n), and Θ(log10n). What is the difference between them, if any?
    21. Suppose you were given two lists of strings (a1, a2, …, an) and (b1, b2, …, bn). Post's Correspondence Problem is to find a sequence of integers <i1, i2, …, ik> (each from {1…n}) such that

      ai1 & ai2 & … & aik = bi1 & bi2 & … & bik

      For example, if A = ("able", "eci", "gek", "foo", "d", "un") and B = ("", "cidabl", "dab", "oo", "e", "und") then a solution is the sequence <6,5,2,5,1>. It turns out that any algorithm to solve this problem has complexity Ω(∞). What does this mean? Give a justification for this.

    22. Prove or disprove: λn.3n ∈ O(2n).
  4. Arrays
    1. Write a recursive function to determine whether or not the items in an array of numbers appear in increasing order.
    2. Write a function that takes in a list (or array) of integers v, and an integer n, and returns whether or not there is a subset of the elements in v which sums to n. In this problem the sum of the empty set of integers is 0.
    3. Write a Java method that takes in an array of integers a and an integer k, whose value must be a legal index of a, and swaps the two subarrays a[0..k-1] and a[k..a.length-1]. For example if you input the array [8, 4, 5, 2, 9, 1, 7, 6] and the integer 3 then your method should modify the array to be [2, 9, 1, 7, 6, 8, 4, 5].
    4. Write a Java method that takes in an array of ints and an object of a class that implements the following interface
      interface Function {
          int evaluate(int x, int y);
      }
      
      and returns the value obtained by accumulating the result of applying the function to each element of the array. For example, if you had the array [5, 7, 6, 1] and the function
      Function plus = new Function() {
          int evaluate(int x, int y) {return x + y;}
      };
      
      your method should return the value 19.
    5. Write a Java method that takes in an array of ints (called a) an int (called x), and an object (called f) of a class that implements the following interface
      interface Function {
        int evaluate(int x, int y);
      }
      
      and returns the list obtained by applying f to x and each element of the array in order. For example, if you had
      int[] a = new int[]{5, 7, 6, 1};
      Function subtract = new Function() {
          int evaluate(int x, int y) {return x - y;}
      };
      
      and you called your method like this:
      int[] b = whateverYouCallTheMethod(a, 2, subtract);
      
      then your method should return the array [-3, -5, -4, 1].
    6. Write a recursive function to determine whether a given array is sorted. Then write it non-recursively.
  5. Lists
    1. Write a utility method that takes a java.util.List and returns a new list made by duplicating each element in the original as in this example: stutter([A,B,C]) = [A,A,B,B,C,C].
    2. Write a utility method that interleaves two java.util.List objects. That is, interleave([A,Z,G,Q], [P, X, R]) would return a new list [A, P, Z, X, G, R, Q].
    3. Write a non-recursive function to determine whether or not a given element is a member of a singly-linked list.
    4. Write a Java method that takes a singly linked list of nodes and returns a new list containing every other element of the original list. For example if your input list was ["dog", "car", "bat", "mop", "rug"] then your method should return ["dog", "bat", "rug"]. The result should contain new node objects.
    5. Write two recursive methods for removing all the 0s from a linked list of integers. The first one should do a destructive removal of the zeros; the second should leave its input unchanged and return a new list which is like the original except with the zeros removed.
    6. One way to link together a bunch of objects is to store objects in nodes which bind the object together with a reference to the next object in the chain. For example
      class Node {
          public Object data;
          public Node next;
      }
      
      The last node in the chain has a value of null for its field called next. Without arguing the brilliance or stupidity of the public fields (gasp!) write a Java method that takes in a node and removes all nodes containing Integer objects that appear after the given node in the chain. You may not construct any new nodes, just unhook the ones you are supposed to remove from the chain.

      Extra credit: It is possible for some smartalec to make one of the nodes' next field reference a node earlier in the chain, making an algorithm that stops when it sees a null actually loop forever. Make your method be tolerant of this and stop whenever it detects such a loop.

    7. Write a Java method that takes a singly linked list and modifies the list by exchanging the first and second elements, the third and fourth elements, the fifth and sixth, etc. by moving references only! That is, you may not change the data elements within nodes: you can only relink existing nodes in such a way that you get the desired result.
    8. Suppose you were given a singly linked list of objects. Write a Java method to reverse this list by leaving all the objects in the nodes that contain them while moving links around.
    9. Complete the ancestors and descendants method of the following class. Write them recursively.
      class Person {
          private String name;
          private Person mother;
          private Person father;
          ...
          public Set<Person> ancestors() {...}
          public Set<Person> descendants() {...}
      }
      
  6. Collections
    1. Both stacks and queues are a kind of priority queue. What exactly does this statement mean?
    2. Given a BoundedQueue of capicity 4 which is initially empty, draw pictures of the queue after each of the following steps.
          enqueue a
          enqueue b
          enqueue c
          dequeue
          enqueue d
          dequeue
          enqueue e
          enqueue f
          dequeue
          dequeue
      
  7. Writing ADTs From Scratch
    1. Implement a queue class, from scratch, in which the queue contents are allocated in fixed-size chunks (that is, as a linked list of arrays).
    2. Write an interface for an abstract data type Polynomial. Make sure it has a fairly complete set of operations. If you don't know what a polynomial is, ask a friend who has taken algebra.
    3. Implement a class for the following kind of sequence (you'll have to name it, too). An object of this class can be opened in either read-only or write-only mode. Items are read in order starting from the first element; though at any time you may reset the read pointer to the first element. Writing to the sequence is allowed only by appending items to the end; at any time you can erase all the items in the sequence (there is no way to selectively delete an item). A sequence must be closed before its mode can be changed. Provide operations to query the current size, the current mode, etc. Declare relevant exceptions. You may choose either an array-based or a linked representation.
  8. Trees
    1. Explain precisely the difference between height and depth in the context of trees.
    2. Write methods for a general oriented tree class to
      1. return the list of ancestors of a node
      2. return the mirror image of a tree
      3. return the height of a tree
      4. remove all nodes from the tree that do not meet a given condition
    3. How many nodes are there on level j of the binomial tree Bk?
    4. How many nodes are there in the binomial tree Bk?
    5. Draw the binary tree whose inorder traversal is E J F A D G H C B I, and whose preorder traversal is A E F J B C D G H I, or explain why no such tree exists.
    6. Draw the binary tree whose preorder traversal is E A S Y and whose inorder traversal is Y E S A, or explain why no such tree exists.
    7. Give an expression for the minimum height k-ary tree with n nodes.
    8. If possible, draw the binary tree with postorder traversal H G F D C E A B and inorder traversal is C G H D F B E A, or state why no such tree can exist.
    9. Draw the binary tree with preorder A B C E D F and inorder A C E F D B or prove that no such tree exists.
    10. If the preorder and in order of a binary tree are the same, what does the tree look like?
    11. If the breadth-first and post order of a binary tree are the same, what does the tree look like?
    12. Write the mathematical expression for the number of nodes on the last two levels of a minimum height binary tree of n nodes.
    13. One way to represent a binary tree is as an array of records in which each record has three fields: one for the node data and two for the indices (into the array) of its two children. Draw the binary tree given by the following:
      1Gamma00
      2Beta13
      3Epsilon65
      4Omega27
      5Sigma00
      6Alpha00
      7Tau80
      8Delta00
    14. Consider the binary tree implementation scheme described in the previous problem.
      1. Write a class (or type) declaration for this structure.
      2. How can you determine whether a given element in the tree is a leaf?
      3. How do you find the root of the tree?
    15. Write a non-recursive function to compute the number of leaves in a binary tree.
    16. Draw the complete ternary tree of 26 nodes.
    17. In the array representation of a ternary tree, what is the index of the rightmost child of the node with index i? (Recall that the root has index 1.)
    18. Give a closed-form formula for the maximum number of empty spaces in the array representation of a k-ary tree of height h. Can you tell from the phrasing of this question that your answer should be a formula in terms of k and h?
    19. Write the expression tree for the following Java expression
      (a = 3) >= m >= g . x [ 4 ] * ~ 6 || y %= 7 ^ 6 & p
      
    20. Write a recursive instance method for a BinaryTree class that returns a collection of the data elements in the internal (non-leaf) nodes of a binary tree. For example, in the binary tree
                   A
                 /   \
               B       C
              / \       \
             D   E       G
                /
               F
      
      your method needs to return the collection [A, B, E, C].
  9. Sets and Dictionaries
    1. Give a sequence of five integers such that if each integer in the sequence is inserted, in order, into an initially empty splay tree, the resulting splay tree is completely degenerate. If this is not possible, state why it is impossible.
    2. Let B be a binary search tree containing the numbers 1 through n. We may compute the number of possible input orderings (permutations) of these numbers that produce B, by counting the leaves of a tree B' formed from B. Describe how to construct B'.
    3. Of the 3628800 possible insertion sequences of the numbers 1 through 10, how many of them produce the binary search tree (4 (2 (1) (3)) (7 (5 () (6)) (9 (8) (10))))?
    4. Give general guidelines for choosing between a TreeSet and a HashSet.
    5. Draw all possible binary search trees containing the integers 1 through 4. How many such BSTs are there? (Hint: Remember what Catalan numbers are?) How many of these are AVL trees?
    6. Show the binary search tree that results from inserting, in order (into an initially empty tree), the values 20 6 4 8 15 22 11 13 14. Repeat for an AVL tree, a red-black tree, a splay tree, a (2,3)–tree, and a (2,4)–tree.
    7. Show the binary search tree that results from inserting, in order (into an initially empty tree), the values 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15. Repeat for an AVL tree, a red-black tree, a splay tree, a (2,3)–tree, and a (2,4)–tree.
    8. Show the binary search tree that results from inserting, in order (into an initially empty tree), the values 16 28 95 108 100 119 33 97 30 105. Repeat for an AVL tree, a red-black tree, a splay tree, a (2,3)–tree, and a (2,4)–tree.
    9. Show the binary search tree that results from inserting, in order (into an initially empty tree), the values 10, 90, 80, 20, -5, 1, -6, 6. Repeat for an AVL tree, a red-black tree, a splay tree, a (2,3)–tree, and a (2,4)–tree.
    10. Draw the tallest possible red-black tree with 17 nodes.
    11. Write (a) a recursive and (b) a non-recursive algorithm for finding the fewest number of nodes that an AVL tree of height h may have.
    12. Is every full binary tree also an (a,b)-tree? If so, give the values for a and b. If not, disprove.
    13. In the following tree, indicate for each node whether the first step in splaying it would be a zig, a zig-zig, a zig-zag, or none of the above.
                        R
                      /
                    N
                  /  \
                K      P
              /   \      \
            E       L      Q
          /  \        \
        D      I        M
             /   \
           G       J
         /   \
       F       H
      
  10. Sorting
    1. Why is Quicksort usually faster than Mergesort when the data to be sorted is stored in an array?
    2. Give an Θ(n) algorithm to sort an array of shorts in Java.
    3. One of the nice features of Quicksort is that it allows a great deal of parallelism in an implementation. After partitioning, the slices on either side of the pivot can be sorted in parallel. It is very easy to set things up to do this in languages such as occam, but tedious in Ada and Java. Code up a parallel version of Quicksort in Ada or Java and explain why it is messy.
    4. Describe the best and worst case situations for Heapsort. That is, state which permutations of the input array result in the best and worst case running times for the algorithm.
    5. Describe the best and worst case situations for Treesort.
    6. Describe the best and worst case situations for Insertionsort. Why is its best case better than the best case for the other sorting algorithms you know? Why is its worst case worse than the worst case for the other algorithms?
  11. Priority Queues
    1. What is the height of a (binary) heap with n elements?
    2. Prove that the running time of the standard buildheap algorithm, for turning an array, in place, into a heap is Θ(n), where n is the number of elements in the array.
  12. Graphs
    1. Explain informally but precisely why the problem "Does graph G have a vertex cover of size less than or equal to k?" is in NP.
    2. A problem that looks very much like the previous problem, namely "Does graph G have a vertex cover of size greater than k?" is also in NP. In fact, its time complexity is Θ(1). Prove this. You can write a one-line function for your proof.
    3. Does the adjacency list representation of a graph have any advantages over other representations? If so, what are these advantages?
    4. Does the following function really determine whether or not a given simple, undirected graph has cycles? (Recall that a cycle in a simple undirected graph is a simple circuit whose length is greater than or equal to 3.) I mean, every time I draw up a graph with as many or more edges than nodes I find cycles. Am I missing something, or have I really found an O(1) solution?
          public static boolean hasCycles(Graph g) {
            return g.numberOfEdges() >= g.numberOfNodes();
          }
      
      Why or why not?
    5. Prove that a graph is 2-colorable if and only if it has no odd-length circuits (König's Theorem).
    6. Give a function to find a "nearly maximal" independent set for a given simple undirected graph, using a greedy algorithm. Then give an example of a graph for which your algorithm gives a sub-optimal answer.
    7. Use graph theory to prove that in any group of six people, there are either three people that all know each other or three mutual strangers. (Hint: talk about cliques and independent sets.)
    8. If you had an algorithm to solve the traveling salesperson problem you could use it to determine whether or not a graph had a Hamilton Circuit. How?
    9. The complement of a simple, undirected graph G = (V, E) is the graph GC = (V, E') where E' = {(u,v) | (u,v) ∉ E}. Less formally, GC contains exactly those edges that are not in G.
      1. Is it easier to compute the complement of a graph under an adjacency matrix or an adjacency list representation?
      2. Write a method of a SimpleUndirectedGraph class that returns its complement.
      3. What is the (time) complexity of your algorithm?
    10. Show how to find, in polynomial time, the smallest independent set that is also a vertex cover.
    11. How many edges are there in the complete graph Kn?
    12. Traverse the following graph (a) breadth-first and (b) depth-first starting at node F:

      A — B — C — D — E — F — G — H — I — J

    13. Note that, for a simple, undirected graph with n nodes, the n × n adjacency matrix M is space-inefficient.
      1. Exactly how many entries in the matrix M are actually required to represent the graph?
      2. To save space we could store the significant entries of M in a one-dimensional array A. We would then need a function f such that M(i, j) = A(f(i, j)). Write the closed-form expression for f. (Assume that nodes are indexed from 1...n.)
    14. Is a Hamilton Path guaranteed to exist in a simple, undirected graph whenever the number of edges exceeds twice the number of nodes? Why or why not?
    15. Prove that the sum of the degrees of the nodes in a simple, undirected graph is twice the number of edges in the graph.
    16. A relation is irreflexive iff ∀x. ~R(x,x) and is asymmetric iff ∀x y. R(x,y) ⇒ ~R(y,x). Prove that a transitive irreflexive relation is asymmetric.
    17. Determining whether a simple, undirected graph is 3-colorable is NP-complete, but determining whether it is 2-colorable is in P. Give an Θ(e) algorithm for determining 2-colorability.
    18. Suppose you were given (1) an algorithm to compute the complement of a simple, undirected graph and (2) an algorithm to find the maximum clique in a simple, undirected graph. How could you then compute the smallest vertex cover?
    19. Write functions to compute the smallest dominating set and the maximum clique of a simple undirected graph.
    20. What is the chromatic number of a full ternary tree of height n?
    21. Suppose I gave you an algorithm, to determine for some value n, whether or not a simple, undirected graph G had a spanning tree in which no node had degree larger than n. Show how to use this algorithm to determine whether or not a graph has a Hamilton Path.
    22. Prove that if a simple undirected graph G is a tree then GC is either (1) connected or (2) consists of two blocks: one containing only one node and the other a clique of the remaining nodes.
    23. Give a polynomial time algorithm that returns "one of the smallest" vertex covers in a graph. It doesn't have to return the smallest vertex cover (it is not likely that you could do this in polynomial time anyway, why?) but its size should be close to minimal.
    24. Give the (time) complexity of Prim's algorithm for finding the minimum spanning tree of a graph, assuming that the priority queue is implemented as a heap.
  13. Advanced Algorithms
    1. Prove by induction that the number of subsets of a set with n elements is 2n.
    2. Write a function to return the powerset of a discrete set.
    3. Write a function to return the sum of subsets of a set of integers. For example the sum of subsets of the set {4,7} is 0 + 4 + 7 + (4 + 7) = 22.
    4. Prove that the number of permutations of a set of n elements is n!. This problem is easier than you might think.
    5. In mathematics, the notation fk(x) denotes the repeated function application:

      f (f (... f ( x ) ...))

      where there number of fs is k. Write a function to compute f k(x).

    6. A logical formula is said to be satisfiable if and only if there exists some assignment of values to variables such that the formula evaluates to True. For example, the formula
          (x1 or x3 or not x2) and (x2 or not x3)
      
      is satisfiable under the assignment x1 = True, x2 = False, x3 = False.
      1. Is this formula satisfiable?
            (x1 or x3 or x5) and (x1 or not x2 or x4) and (not x3 or x4 or x5) and (x2 or not x3 or x5)
        
      2. Explain how you could determine if a graph were 3-colorable using a pre-existing algorithm for determining satisfiablility.
    7. Is it easier or harder (from a computational point of view) to determine satisfiability or unsatisfiability?
    8. It is thought that P ≠ NP because finding solutions seems to be a more difficult task than checking the validity of a candidate solution. Analyze the stable marriage problem to determine if it is ``easier'' (more efficient) to check that a given configuration is stable than to find a stable solution.
    9. If you were given the problem to display all solutions to the 8-queens problem you would have to examine and test all possible configurations.
      1. How many configurations are there?
      2. If you could examine one billion configurations per second, how long would it take you (at least) to find all solutions to the 30-queens problem?
    10. Consider the function C defined recursively as follows:
          C(n, k) = 1, if k = 0 or k = n
                  = C(n-1, k-1) + C(n-1,k) if 0 < k < n
                  = undefined, otherwise
      
      It can be shown that C can also be defined non-recursively:
          C(n,k) = n! / (k!(n-k)!)
      
      Give the worst-case complexity of (a) the naïve recursive, (b) the non-recursive algorithms for computing C(n, k).
    11. Implement the function C above using dynamic programming.
    12. Does the stable marriage problem always have a solution, provided the inputs (i.e. the preference lists) are legal? Give a proof or a counterexample.
    13. Write an efficient function that returns the list of prime factors of a given natural number. What is the complexity of your algorithm? Are you sure?