1.0 - Dynamic Programming

🌱 Using Dynamic Programming, we can cause massive speed improvements: from exponential-time to polynomial time

🌱 Problems can have different optimal sub-structures, that impact the efficiency of the final solution

1.1 - Memoisation

1.2 - Fibonacci using Dynamic Programming

🌱 Many problems are naturally expressed recursively. However, recursion can be computationally expensive.



We can also construct a memoised Fibonacci algorithm

Assume that array T is a global variable, and we will never require a Fibonacci number past N

fibonacci_init() T = new int[N] for i = 1..N T[i] = null T[1] = 1 T[2] = 1 fibonacci_memoised(n) if T[n] == null // Check if we have already computed a solution T[n] = fibonacci_memoised(n-1) + fibonacci_memoised(n-2) return T[n]

1.3 - Solving Problems using Dynamic Programming

🌱 Solving problems using recursion is often intuitive and elegant, however it can be massively inefficient.

If:

  1. The problem has the optimal substructure property, and
  2. It’s recursive solution has overlapping sub-problems,

Then dynamic programming techniques may apply. Doing this, we get an efficient (polynomial-time) implementation for the loss of elegance.

1.4 - Longest Common Subsequence (LCS)

🌱 Find the longest (non-contiguous) sequence of characters shared between two strings

1.4.1 - Determine Base Cases

LCS(,S2)= LCS(S1,)=LCS(S1X,S2X)=LCS(S1,S2)XLCS(S1X,S2Y)=max(LCS(S1,S2Y),LCS(S1X,S2)    when XY\begin{aligned} \text{LCS}(\langle\rangle, S_2) &=\ \text{LCS}(S_1, \langle \rangle)=\langle \rangle\\ \text{LCS}(S_1\cdot X, S_2\cdot X)&=\text{LCS}(S_1, S_2)\cdot X\\ \text{LCS}(S_1\cdot X, S_2\cdot Y)&=\max(\text{LCS}(S_1, S_2\cdot Y), \text{LCS}(S_1\cdot X, S_2)\ \ \ \ \text{when } X\ne Y \end{aligned}

1.4.2 - Implementing Length of LCS Algorithm

LCS(,S2)=LCS(S1,)=0LCS(S1X,S2X)=LCS(S1,S2)+1LCS(S1X,S2Y)=max(LCS(S1,S2Y),LCS(S1X,S2))   when XY\def\lcs{\text{LCS}} \begin{aligned} \lcs(\langle\rangle, S_2)&=\lcs(S_1, \langle\rangle)=0\\ \lcs(S_1\cdot X, S_2\cdot X)&=\lcs(S_1, S_2)+1\\ \lcs(S_1\cdot X, S_2\cdot Y)&=\max(\lcs(S_1, S_2\cdot Y), \lcs(S_1\cdot X, S_2))\ \ \ \text{when } X\ne Y \end{aligned}

1.4.3 - Recursive, Non-Dynamic Implementation

1.4.4 - Recursive, Dynamic Implementation

lcs_length_dyn(S1, S2, n, m) T = new int[n+1][m+1] // Insert base cases into the table for i = 1 to n T[i,0] = 0 for j = 1 to m T[0,j] = 0 for i = 1 to n for j = 1 to m if S1[i] == S2[j] T[i,j] = T[i-1, j-1] + 1 else if T[i-1, j] > T[i, j-1] T[i,j] = T[i-1, j] else T[i,j] = T[i, j-1]

1.4.5 - Reconstructing the Path