Buffer Day 1 - Problems

Complete the following coding problems. Start by coding all of them up on paper. This is intended to help you practice writing code as you will be asked to on quizzes and exams in this and future CS classes, and likely also in internship and job interviews.

Once you’ve written out code for all the problems and convinced yourself as thoroughly as possible that they will work, go back to each solution, testing and debugging with the help of a Java compiler (if available). Unless someone in your group has something already set up locally, I recommend using an online IDE such as repl.it to get an easily-accessible Java development environment.

Some of these functions are not trivial to test - for example, you will need to create the BinaryTree class and build a number of example trees to run your isFull method on to make sure that it handles all possible cases.

  1. The computation \(a^x\) (i.e., raising \(a\) to the \(x\) power) can be described iteratively as multiplying \(a\) by itself \(x\) times. The obvious iterative algorithm for this is \(O(x)\), assuming a single multiplication takes constant time. Implement that algorithm below:

    /** Compute a to the power of x. Precondition: x >= 0. */
    public static int exponentiate(int a, int x) {
    
    }
  2. It turns out that an \(O(\log x)\) (i.e., much faster!) algorithm exists for computing \(a^x\). It makes use of a recursive definition that leverages the following two mathematical facts in a recursive definition of exponentiation: \[ a^{2k} = a^k * a^k \\ \]

    \[ a^{k+1} = a * a^k \]

    Come up with such a recursive definition and implement the following method to compute it. Don’t worry too much about the runtime analysis - if the approach uses more than a bit less than \(x\) multiplications to compute \(a^x\), you’re probably on the right track.

    /** Compute a to the power of x. Precondition: x >= 0. */
    public static int exponentiateFaster(int a, int x) {
    
    }
  3. We will use the following binary tree class for this problem:

    public class BinaryTree {
      int value;
      BinaryTree left;
      BinaryTree right;
    }

    Implement the following method:

    /** Return whether t is the root of a full binary tree.
      * A full binary tree is a binary tree in which every node
      * is either a leaf or has two children. */
    public static boolean isFull(BinaryTree t) {
    
    }
  4. Implement the following method. You should not assume you have access to a HashMap class - take advantage of the precondition.

    /** Return the mode (i.e., most frequently occurring value) in A.
      * If multiple values appear most frequently, return the smallest of them.
      * Precondition: A is not null, not empty, and is in sorted order. */
    public static int mode(int[] A) {
    
    }
  5. The problem below is a realistic software engineering interview practice question. A couple suggestions: start by coming up with a brute-force solution without concern for efficiency; describe that solution (perhaps using pseudocode) in enough detail to run it through the given examples to make sure it works. Then, think about whether there are ways to improve the asymptotic runtime. Think through any tools you may have in your toolbox (e.g., data structures you learned in 145, and anything we’ve learned in this class so far).

    Problem Statement

    Given a list of n integers arr[0..(n-1)], determine the number of different pairs of elements within it which sum to k.

    If an integer appears in the list multiple times, each copy is considered to be different; that is, two pairs are considered different if one pair includes at least one array index which the other doesn’t, even if they include the same values.

    public static int numberOfWays(int[] arr, int k) {
    
    }
    Input
    Output

    Return the number of different pairs of elements which sum to k.

    Example 1

    n = 5

    k = 6

    arr = [1, 2, 3, 4, 3]

    output = 2

    The valid pairs are 2+4 and 3+3.

    Example 2

    n = 5

    k = 6

    arr = [1, 5, 3, 3, 3]

    output = 4

    There’s one valid pair 1+5, and three different valid pairs 3+3 (the 3rd and 4th elements, 3rd and 5th elements, and 4th and 5th elements).