Reaves.dev

v0.1.0

built using

Phoenix v1.7.17

Dynamic Programming

Stephen M. Reaves

::

2025-01-12

Using the Dynamic Programming approach to solve Fibonacci, LIS, and LCS problems

Summary

How can we store previous subproblems and use that to quickly solve larger problems? This is particularly useful when naive solutions include recomputing some problems. This technique typically involves defining the subproblem in words, then defining a recurrenc relation.

Contents

Fibonacci Numbers

Fn={0n=01n=1Fn1+Fn2n>1F_n = \begin{cases} 0 & n = 0 \1 & n = 1 \F_{n-1} + F_{n-2} & n > 1\end{cases}

Recursive Algorithm

Fib1(n):
  if n == 0:
    return 0
  if n == 1:
    return 1
  return Fib1(n-1) + Fib1(n-2)

Runtime:

T(n)O(1)+T(n1)+T(n2) T(n) \le O(1) + T(n-1) + T(n-2)

Runtime scales with the Fib numbers (T(n)Fn T(n) \ge F_n ) which is exponential.

This is becase we are computing some solutions multiple times:

Ganbn-1a->bcn-2a->cdn-2b->den-3b->efn-3c->fgn-4c->ghn-3d->hin-4d->ijn-4e->jkn-5e->kln-4f->lmn-5f->mnn-5g->non-6g->o

Dynamic Algorithm

Fib2(n):
  F[0] = 0
  F[1] = 1
  for i in range(2,n):
    F[i] = F[i-1] + F[i-2]
  return F[n]

Runtime is O(n)

Steps to Solve DP problems

If the definition is not possible, you can strengthen it and prove the stronger version.

Largest Increasing Subsequence (LIS)

Input: n numbers a1,a2,,an n \text{ numbers } a_1, a_2, \ldots, a_n

Goal: find length of LIS

Gru574-3911045893
substring
Set of consecutive elements
Gru574-3911045893
subsequence
Subset of elements in order (can skip)
Gru574-3911045893

Longest Increasing Subsequences is:

Gru574-3911045893

DP Solution

Let L(i)= length of LIS on a1,a2,,ai and includes ai L(i) = \text{ length of LIS on } a_1, a_2, \ldots, a_i \text{ and includes } a_i

GA574-3911045893L121 1324 34563

L(i)=1+maxj{L(j):aj<ai&j<i} L(i) = 1 + \max_j \lbrace L(j) : a_j < a_i &amp; j < i \rbrace

LIS(A):
  for i in range(0,n):
    L[i] = 1
    for j in range(0,i):
      if A[j] < A[i] & L[i] < 1 + L[j]:
        L[i] = L[j] + 1

  max = 0
  for i in range(1,n):
    if L[i] > L[max]:
      max = i

  return L[max]

Running time is O(n2) O\left(n^2\right)

Longest Common Subsequence (LCS)

Input: 2 Strings

Goal: Find the length of the longest string which is a subsequence of both X and Y

Attempt 1

For i where 0in \text{For } i \text{ where } 0 \le i \le n

let L(i)= length of LCS in x1,,xi and y1,,yi \text{let } L(i) = \text{ length of LCS in } x_1, \ldots, x_i \text{ and } y_1, \ldots, y_i

When xi=yi,L(i)=1+L(i1) x_i = y_i, L(i) = 1 + L(i-1)

When xiyi x_i \neq y_i , we can’t know what previous sequence it was matched on becuase X and Y have different lengths.

We need to store two parameters, one for the length in X, and another for Y

Attempt 2

For i&j where 0in&0jn \text{For } i &amp; j \text{ where } 0 \le i \le n &amp; 0 \le j \le n

let L(i,j)= length of LCS in x1,,xi and y1,,yj \text{let } L(i,j) = \text{ length of LCS in } x_1, \ldots, x_i \text{ and } y_1, \ldots, y_j

Recurrence

L(i,j)={0if i=00if j=0max{L(i1,j),L(i,j1)}if i&j>0&xiyj1+L(i1,j1)if i&j>0&xi=yj L(i,j) = \begin{cases} 0 & \text{if } i = 0 \ 0 & \text{if } j = 0 \ \max\lbrace L(i-1,j),L(i,j-1) \rbrace & \text{if } i &amp; j > 0 , &amp; x_i \neq y_j \ 1 + L(i-1,j-1) & \text{if } i &amp; j > 0 , &amp; x_i = y_j \end{cases}

Or more simply, for i,j>0 i, j > 0

L(i,j)={max{L(i1,j),L(i,j1)}if xiyj1+L(i1,j1)if xi=yj L(i,j) = \begin{cases} \max\lbrace L(i-1,j),L(i,j-1) \rbrace & \text{if } x_i \neq y_j \ 1 + L(i-1,j-1) & \text{if } x_i = y_j \end{cases}

LCS(X,Y):
  for i in range(0,n):
    L[i][0] = 0
  for j in range(0,n):
    L[0][j] = 0

  for i in range(1,n):
    for j in range(1,n):
      if X[i] == Y[j]:
        L[i][j] = 1 + L[i-1][j-1]
      else:
        L[i][j] = max(L[i][j-1], L[i-1][j])

  return L[n][n]