Top-Down DP - G5 - II (With Code)
Top-Down DP - G5 - II (With Code)
Programming
A top-down approach
Part II
1
Common DP Variants
2
0/1 Knapsack
● Knapsack problems generally involve filling a limited container with
items where we want to count or optimize some quantity associated
with the items.
● Problem Link
3
0/1 Knapsack
● Start with what constitutes a good substructure. How to break down
the problem ?
● Consider the substructure starting from the index i.
● What is/are going to be the state/states?
4
0/1 Knapsack
● For the sub-problems starting from the i-th index we can categorize
the subproblems into two.
5
0/1 Knapsack
● For the sub-problems starting from the i-th index we can categorize
the subproblems into two.
6
0/1 Knapsack
● Thus we can pick the item index i and the remaining capacity W of our
knapsack as the state
● Since we are aiming for maximum value we will be taking the maximum
of the two.
7
0/1 Knapsack
● What about the base cases?
if i >= len(wt) or W == 0:
return 0
8
0/1 Knapsack - Implementation
def dp(i, W):
if i >= len(wt) or W == 0:
return 0
Time Complexity = ?
include = 0 Space Complexity = ?
if wt[i] <= W:
include = val[i] + dp(i+1, W - wt[i])
exclude = dp(i+1, W)
memo[(i, W)] = max(include, exclude)
exclude = dp(i+1, W)
memo[(i, W)] = max(include, exclude)
Problem Link
11
Longest Increasing Subsequence
● Finding the longest subsequence of an array such the elements are
increasing
1 3 4 1 2 6 5 7
● A subsequence is a list that can be derived by deleting zero or
more elements of a list. Is it possible to use 0/1 Knapsack? How?
12
Longest Increasing Subsequence
● We can consider each each index and whether we should delete this
index or not to form an increasing subsequence.
1 3 4 1 2 6 5 7
● What are the states?
● The pair (ind, last) forms the state where ind is the current
index and last is the last element in the increasing subsequence we
have built until index ind.
13
Longest Increasing Subsequence
def dp(ind, last):
if ind == len(nums):
return 0 Time Complexity = O(n**2)
Space Complexity = O(n**2)
if (ind, last) not in memo:
include = 0
if last == -1 or nums[last] < nums[ind]:
include = 1 + dp(ind+1, ind)
15
Longest Increasing Subsequence - Implementation
def lengthOfLIS(self, nums: List[int]) -> int:
memo = [0]*len(nums)
def dp(i):
Time Complexity = O(n**2)
if i >= len(nums): Space Complexity = O(n)
return 0
if memo[i] == 0:
memo[i] = 1
for j in range(i+1, len(nums)):
if nums[j] > nums[i]:
memo[i] = max(1 + dp(j), memo[i])
return memo[i]
max_len = 0
for i in range(len(nums)):
max_len = max(dp(i), max_len)
return max_len 16
Longest Common Subsequence
The Longest Common Subsequence (LCS) problem is finding the longest
subsequence present in the given two sequences in the same order.
1 3 4 1 2 6 5 7
2 1 8 3 6 7
What is a good substructure?
17
Longest Common Subsequence
If we know the answer for nums1[i+1 … ] and nums2[j+1 …], how can
we combine them?
○ else the answer can not contain both nums1[i] and nums2[j]
18
Longest Common Subsequence
Problem Link
19
Longest Common Subsequence - Implementation
def longestCommonSubsequence(self, text1: str, text2: str) -> int:
if memo[i][j] == -1:
if text1[i] == text2[j]:
memo[i][j] = 1 + dp(i+1, j+1)
else:
memo[i][j] = max(dp(i+1, j), dp(i, j+1))
return memo[i][j]
return dp(0, 0)
20
Common Pitfalls
21
1. Thinking of greedy approach
Greedy algorithms aim for local optimality, but they can fall short in
finding the global optimum, leading to suboptimal or incorrect
outcomes.
22
2. Incorrect Recurrence Relation
23
3. Lack of proper memoization
24
4. Inefficient time complexity
25
Checkpoint
Link
Practice Questions
N-th Tribonacci Number
Coin Change
Target Sum
Unique Paths
— George Santayana
29