Problem Names Solution Writeups Code
Unique Paths

Create 2D array called dp, since it can only moves right or down, all positions in first row and first column will be 1. Then, for remaining position i, j, dp[i][j] = dp[i-1][j] + dp[i][j-1].

Longest Common Subsequence

Create a 2d vector DP of size text1.size() + 1 and text2.size() + 1. Create two pointers i, j representng text1 and text2. If text1[i] == text2[i], dp[i][j] = 1 + dp[i+1][j+1], else, dp[i][j] = max(dp[i+1][j], dp[i][j+1]). This is bottom-up approach. At last, dp[0][0] stores the answer.

Best Time to Buy and Sell Stock With Cooldown

Create a hash map with key {index, buy}, where index represents the day of buying/selling, while buy represents a boolean of buy/sell. The value of the hash table will be the max profit obtainable. In each day, a person can either buy/cooldown, or sell/cooldown. So only two actions are possible in each day. He must buy before he can sell, and when he sells, idx + 2 need to be applied to enforce the 1 day cooldown period. After looping through the entire prices array, return profit_table[0][buying].

Target Sum

This question is to assign two possible operator to each number, so for each number there is two possible actions, one is to assign + sign and one is to assign - sign. Try them both, and store the result in a hash table with key = {idx, cumulative_sum}, value = number of ways to obtain the target value. After looping through the entire nums array, returned dp[0][0] as it stores the total number of ways. (This is a type of decision tree)

Interleaving String

Having two indices i and j representing string s1 and s2. s3[i+j] will be the current position of s3. For each character in s3 finds if there is a matching character in s1 or s2. If both are matched, need to test two of them. Store the result in a hash map with key = {i, j} and value = true/false, where tru means there exists a solution. This is to prevent repeating tree pattern. So for each i and j, continue only if there is a matching case and dfs(i + 1, j) or (i, j + 1) returns true.

Longest Increasing Path in a Matrix

Create a 2D dp vector to store longest path of each position. Each position guarantees a minimum of 1 length. Create a loop to find the longest path of each position, and find the longest path ever. The way to find longest path is to do DFS, once we find the result we must store the value in the 2D dp so that we do not need to repeat work.

Distinct Subsequences

Do DFS with a hash table with key = {i, j} where i represents the idx of s and j is the idx of t. For each character in s, if s[i] == t[j], do dfs for both include the character and not include the character. If s[i] != t[j], do dfs for not include the character. At last return dp[0][0]. Take note that when j out of bound, it means t is successfully constructed from s, and if s is out of bound, t cannot be constructed using current combination of characters. Also take note that checking t out of bound need to be done first before checking s! This is a problem of decision tree as well.

Edit Distance

If word1.size() == 0, needs word2.size() operations, vice versa. If both word1 and word2 are empty, needs 0 operation. Other than that, create a 2D dp vector to speed up the checking. Note that if word1[i] == word2[j], simply move on to (i+1, j+1). If insertion is needed, it will be (i, j+1). If deletion is needed, it will be (i+1, j), and replacement is also (i+1, j+1). When doing an action, need to +1 additionally. This pattern tells us that we need to do bottom-up dp approach. The size of the dp will be word1.size() + 1 and word2.size() + 1. The last col will be word1.size() in decreasing order, and the last row will be word1.size() in decreasing order. Then for each position (i, j), if word1[i] == word2[j], dp[i][j] = dp[i+1][j+1], else dp[i][j] = min(dp[i+1][j], dp[i][j+1], dp[i+1][j+1]) + 1. Return dp[0][0]. This is a problem of 2D matrix bottom up dp approach.

Burst Balloons

For each balloon exists in the array, pretend it will be popped last, so the earning coin value will be nums[left-1] + nums[curr] + nums[right+1] + dfs(left, i - 1) + dfs(i + 1, right). Left and right pointers will point to the first element and last element, and when out of bound the value is 1. Return dp[1][nums.size()-1] as the answer, since we insert additional 1 at the front and 1 at the back.

Regular Expression Matching

'*' must follow a character. So when encounter a '*', we have two choices, one is don't use it and directly jump to the next, one is to use it, but the leading character must match first. So for each position in pattern p, we check if curr_pos + 1 is a '*', if this is true, when we don't use '*', jump to (s_idx, curr_pos + 2), if used, the condition must be matched and (s_idx + 1, curr_pos). For normal character like the matching alphabets and the '.' character, simply do (s_idx + 1, curr_pos + 1). When either dfs gives false, returned false.