-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
216495b
commit 14343db
Showing
30 changed files
with
13,556 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
|
||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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})); | ||
} | ||
} | ||
|
Oops, something went wrong.