Skip to content

Commit

Permalink
added greedy + dp00
Browse files Browse the repository at this point in the history
  • Loading branch information
CleanestMink126 committed Apr 18, 2019
1 parent 216495b commit 14343db
Show file tree
Hide file tree
Showing 30 changed files with 13,556 additions and 11 deletions.
49 changes: 49 additions & 0 deletions DP/dp00/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Introduction to Dynamic Programming

This homework is due on Thursday, April 25th (see below for submission details).

## Learning Goals

Students will:

- Become familiar with the 5 steps of DP (Subproblems, Guess, Recurrence Relation, Memoize, Solution)
- Apply the 5 steps to algorithms problems
- Be able to design and write their own DP algorithms
- Analyze the runtime of DP algorithms

## Resources

- [Here](https://docs.google.com/presentation/d/1cbpgDX3lnBjJ-oU8Mk94XHLx5wPvmL2Y1U-j3EY_c2A/edit?usp=sharing) is a link to our slides.
- Bae Erik Demaine does an entire series on DP. Today's lecture borrowed elements from the [first one](https://youtu.be/OQ5jsbhAv_M?t=56s)
- [Here](https://youtu.be/OQ5jsbhAv_M?t=6m4s) is the timestamp for his Fibonacci number example. This is a classic DP example, although we chose not to cover it because you don't actually need the Guess step (you almost always do for DP problems)
- [Here](https://youtu.be/OQ5jsbhAv_M?t=32m29s) is the timestamp for his coverage of the shortest paths problem. We went over this in lecture.
- Here's a great DP [tutorial](https://www.topcoder.com/community/data-science/data-science-tutorials/dynamic-programming-from-novice-to-advanced/), if you want more practice implementing algorithms outside of your homework assignments.
- There are a lot of other great resources out there on DP as well. If you find any you think should be added to this list please let us know!

For this homework, we have included a general DP template, but do not feel compelled to use if you would rather not. We have also included a solution to the making-change problem from lecture today.

## Assignment

**Choose 2 of the following problems. Make sure you note what each of the 5 DP steps are for the problem (as done today in lecture). Your NINJA will ask you to explain these 5 steps when you are checked off. Also, note your time/space complexity**

### Dice roll sum

Professor Prava is curious how many 6-sided dice roll sequences there are that reach a sum of `N`. For example, if `N=10`, one possible sequence is: `[6, 2, 2]`. Another is `[2, 6, 2]`. Another is `[3, 3, 3, 1]` Write a function that returns the number of sequences. For `N=0`, return `1` (there is one sequence...the empty sequence `[]`).

### Longest increasing subsequence

Given an unsorted array of integers, what is the length of the longest increasing subsequence? Subsequence is defined as: a sequence that can be derived from the array by removing zero or more elements. Some examples:

- Given `[5, 3, 1, 5, 8, 10]`, the LIS is `[3, 5, 8, 10]`, so your function returns `4`.
- Given `[5, 4, 3, 4, 2, 5]`, the LIS is `[3, 4, 5]`, so your function returns `3`.
- Given `[1, 2, 3]`, return `3`.
- Given `[3, 2, 1]`, return `1`.

### Longest common subsequence

Given two strings, return the length of their longest common subsequence (subsequence defined above). For example, given `NATHAN` and `PRAVA`, the LCS is `AA`, so your function should return `2`.

## Submitting the Assignment
* Go to NINJA hours to get checked off (on or before Thursday, April 25th).
* Be prepared to explain the runtime and the 5 DP steps for each of the problems you solved.
* Complete the [survey](https://forms.gle/PdsWecfxDFVfATqE8).
99 changes: 99 additions & 0 deletions DP/dp00/implementation_guide.tex
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
\documentclass{article}
\usepackage[utf8]{inputenc}

\title{\large{\textsc{\vspace{-1cm}Dynamic Programming Implementation Guide}}}
\date{}

\usepackage{natbib}
\usepackage{graphicx}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{mathtools}
\usepackage[a4paper, portrait, margin=0.5in]{geometry}

\usepackage{listings}

\newcommand\perm[2][n]{\prescript{#1\mkern-2.5mu}{}P_{#2}}
\newcommand\comb[2][n]{\prescript{#1\mkern-0.5mu}{}C_{#2}}
\newcommand*{\field}[1]{\mathbb{#1}}

\DeclarePairedDelimiter\ceil{\lceil}{\rceil}
\DeclarePairedDelimiter\floor{\lfloor}{\rfloor}

\newcommand{\Mod}[1]{\ (\text{mod}\ #1)}

\begin{document}
\maketitle

\subsection*{Bottom-up}

\begin{enumerate}
\item \textbf{initialize memo}

If using an array, make sure you initialize it to the correct size (usually size \texttt{N + 1}, to store all \texttt{N} subproblems plus the base case). If using a hashmap, you don't have to worry about sizing.

\item \textbf{store base case in memo}

\item \textbf{iterate over subproblems}

Using a loop, iterate the indices into your memo over the subproblems. Pay attention to the direction of the dependencies in the recurrence relation. E.g., for \texttt{DP[i] = min(DP[i+1], DP[i+2])}, you must solve the problems in \textit{descending} order for \texttt{i}. Generally speaking, you should solve the smallest problems first.

\item \textbf{solving subproblems}

In your loop, calculate \texttt{DP[key]} (\texttt{key} may be one or more indices, potentially something else) using your recurrence relation. Often you will take the \texttt{min} or \texttt{max} of all possible guesses.

\item \textbf{store answer to subproblems}

Store the result in \texttt{DP[key]}.

\item \textbf{return answer to original problem}

This should be a value in your memo.

\end{enumerate}

\subsection*{Top-down}

\begin{enumerate}

\item \textbf{initialize memo}

In a public facing function, initialize your memo. If using an array, make sure you initialize it to the correct size (usually size \texttt{N + 1}, to store all \texttt{N} subproblems plus the base case). If using a hashmap, you don't have to worry about sizing. If you are using an array, you might want to fill it with a special value to indicate that the subproblems are currently unsolved.

\item \textbf{store base case in memo}

\item \textbf{create private recursive function}

This function's purpose is to return the solution to subproblems (i.e., it returns \texttt{DP[key]}). This function's inputs should contain the memo, the key value(s) for the memo (e.g., \texttt{i} and \texttt{j}), and any other data needed (often the input to your public function is also an input to your private function).

\item \textbf{check if memo has solution}

In the recursive function, check if your memo already contains a solution for the given input key value. If it does, return the value in the memo.

\item \textbf{solving subproblems}

In your recursive function, use your recurrence relation to calculate \texttt{DP[key]}. \textbf{Don't explicitly access values in your memo. Instead, call the recursive function.} For example, for Fibonacci:

\begin{lstlisting}[language=Java]

private int fib_recurs(int i, int[] DP) {
if (DP[i] != -1) return DP[i];
DP[i] = DP[i-1] + DP[i-2]; // don't do this
DP[i] = fib_recurs(i-1, DP) + fib_recurs(i-2, DP); // do this instead
return DP[i];
}

\end{lstlisting}

\item \textbf{store and return answer to subproblem}

Store the answer to the subproblem in your memo and return it (this is shown above)

\item \textbf{return answer to original problem}

In your public function, use your recursive function to solve the problem and return it, e.g., \texttt{return fib\_recurs(10, DP)}.

\end{enumerate}


\end{document}
55 changes: 55 additions & 0 deletions DP/dp00/pset.tex
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@

\documentclass{article}
\usepackage[utf8]{inputenc}

\title{\large{\textsc{Dynamic Programming 00}}}
\date{}

\usepackage{natbib}
\usepackage{graphicx}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{mathtools}
\usepackage[a4paper, portrait, margin=0.8in]{geometry}

\usepackage{listings}


\newcommand\perm[2][n]{\prescript{#1\mkern-2.5mu}{}P_{#2}}
\newcommand\comb[2][n]{\prescript{#1\mkern-0.5mu}{}C_{#2}}
\newcommand*{\field}[1]{\mathbb{#1}}

\DeclarePairedDelimiter\ceil{\lceil}{\rceil}
\DeclarePairedDelimiter\floor{\lfloor}{\rfloor}

\newcommand{\Mod}[1]{\ (\text{mod}\ #1)}

\begin{document}

\maketitle

\subsection*{}


For the problems below, identify the subproblem, guess, recurrence relation, and time complexity using dynamic programming. If you finish, also try coding them up.

\begin{enumerate}

%%%%% PROBLEM 1 %%%%%
\item Professor Prava is curious how many 6-sided dice roll sequences there are that reach a sum of \texttt{N}. For example, if \texttt{N=10}, one possible sequence is: \texttt{6, 2, 2}. Another is \texttt{[2, 6, 2]}. Another is \texttt{[3, 3, 3, 1]]}. Using DP, determine how many sequences there are for any given \texttt{N}.

\item Given an unsorted array of integers, what is the length of the longest increasing subsequence? Subsequence is defined as: a sequence that can be derived from the array by removing zero or more elements. Some examples:

\begin{itemize}
\item Given \texttt{[5, 3, 1, 5, 8, 10]}, the LIS is \texttt{[3, 5, 8, 10]}, so your function returns \texttt{4}.
\item Given \texttt{[5, 4, 3, 4, 2, 5]}, the LIS is \texttt{[3, 4, 5]}, so your function returns \texttt{3}.
\item Given \texttt{[1, 2, 3]}, return \texttt{3}.
\item Given \texttt{[3, 2, 1]}, return \texttt{1}.
\end{itemize}

\item Given two strings, return the length of their longest common subsequence (subsequence defined above). For example, given \texttt{NATHAN} and \texttt{PRAVA}, the LCS is \texttt{AA}, so your function should return \texttt{2}.

\end{enumerate}


\end{document}
36 changes: 36 additions & 0 deletions DP/dp00/src/DPTemplate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

public class DPTemplate {

//PUBLIC FUNCTION
public long publicFunction(/* User inputs */){

/** INITIALIZE THE MEMO */

// CALL RECURSIVE FUNCTION ON PROBLEM THAT YOU WANT TO SOLVE, RETURNING THE ANSWER

return 0;


}

private long recursiveFunction(/* Only arguments that are part of subproblem, and your memo */){

// BASE CASES


/** HAS THIS BEEN MEMOIZED? */


// RECURRENCE RELATION, CALL YOUR RECURSIVE FUNCTION


/** UPDATE THE MEMO */


// RETURN THE ANSWER

return 0;

}

}
10 changes: 10 additions & 0 deletions DP/dp00/src/DiceRollSum.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
public class DiceRollSum {

// Runtime: TODO
// Space: TODO
public static int diceRollSum(int N) {
// TODO
return 0;
}

}
9 changes: 9 additions & 0 deletions DP/dp00/src/LongestCommonSubsequence.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
public class LongestCommonSubsequence {

// Runtime: TODO
// Space: TODO
public static int LCS(String S1, String S2) {
// TODO
return 0;
}
}
9 changes: 9 additions & 0 deletions DP/dp00/src/LongestIncreasingSubsequence.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
public class LongestIncreasingSubsequence {

// Runtime: TODO
// Space: TODO
public static int LIS(int[] A) {
// TODO
return 0;
}
}
26 changes: 26 additions & 0 deletions DP/dp00/src/MakingChange.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

public class MakingChange {

private static int coinsNeededRecurs(int i, int[] denominations, int[] DP) {
// base case
if (i == 0) return 0;
// have we already solved this subproblem
if (DP[i] != -1) return DP[i];
// DP[i] = min(DP[j] + 1) for j in denominations
int answer = Integer.MAX_VALUE;
for (int j : denominations)
if (j <= i) answer = Math.min(coinsNeededRecurs(i - j, denominations, DP) + 1, answer);
// store our answer and return it
DP[i] = answer;
return answer;
}

// Given N = 30, and coinDenominations = [1, 10, 25], returns 3
public static int minCoinsNeeded(int N, int[] coinDenominations) {
int[] DP = new int[N + 1];
for (int i = 0; i < DP.length; i++) {
DP[i] = -1; // set a special empty value
}
return coinsNeededRecurs(N, coinDenominations, DP);
}
}
47 changes: 47 additions & 0 deletions DP/dp00/test/DiceRollSumTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@


import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class DiceRollSumTest {
@Test
public void testOne() {
assertEquals(1,DiceRollSum.diceRollSum(0));
}

@Test
public void testTwo() {
assertEquals(2,DiceRollSum.diceRollSum(2));
}

@Test
public void testThree() {
// All the sequences that sum to 4:
// 4
// 3, 1
// 2, 2
// 2, 1, 1
// 1, 3
// 1, 2, 1
// 1, 1, 2
// 1, 1, 1, 1
assertEquals(8,DiceRollSum.diceRollSum(4));
}

@Test
public void testFour() {
assertEquals(16,DiceRollSum.diceRollSum(5));
}

@Test
public void testFive() {
assertEquals(125,DiceRollSum.diceRollSum(8));
}


@Test
public void testSix() {
assertEquals(492,DiceRollSum.diceRollSum(10));
}

}
43 changes: 43 additions & 0 deletions DP/dp00/test/LongestIncreasingSubsequenceTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class LongestIncreasingSubsequenceTest {
@Test
public void testOne() {
assertEquals(0, LongestIncreasingSubsequence.LIS(new int[]{}));
}

@Test
public void testTwo() {
assertEquals(4, LongestIncreasingSubsequence.LIS(new int[]{5, 3, 1, 5, 8, 10}));
}

@Test
public void testThree() {
assertEquals(3, LongestIncreasingSubsequence.LIS(new int[]{5, 4, 3, 4, 2, 5}));
}

@Test
public void testFour() {
// 1, 4, 7, 8, 12, 19
assertEquals(6, LongestIncreasingSubsequence.LIS(new int[]{8, 1, 4, 9, 4, 2, 10, 8, 7, 8, 12, 3, 19}));
}

@Test
public void testFive() {
assertEquals(1, LongestIncreasingSubsequence.LIS(new int[]{5, 4, 3, 2, 1}));
}

@Test
public void testSix() {
// 1, 3, 9, 18, 19, 20 is one of the LISs
assertEquals(6, LongestIncreasingSubsequence.LIS(new int[]{5, 3, 1, 7, 3, 9, 2, 1, 8, 30, 2, 18, 19, 13, 20, 7, 10, 16}));
}

@Test
public void testSeven() {
assertEquals(5, LongestIncreasingSubsequence.LIS(new int[]{5, 4, 3, 2, 1, 1, 2, 3, 4, 5}));
}
}

Loading

0 comments on commit 14343db

Please sign in to comment.