2D DPπ
Best Time to Buy & Sell Stocks with Txn Feeπ
- Best Time to Buy and Sell Stocks with Transaction Fee : might look like above problems but its not because we can sell at will.
- Cue to DP : Maximize profit (try DP!)
- DnC criteria : think about all possible txn, so we can buy on 6th day and sell on 1st day , like that there could be many element of the set. Now problem is finding subproblem which provide us mutually exclusive & exhaustive sets.
- We could purchase on first day and donβt buy on first day. Letβs try to related the subproblem to original problem
- Purchase on 0th day
- : max profite you can make from , assuming first thing we do is sell
- Donβt purchase on 0th day
- : max profit that you can make from , assuming you start with a buy
- Here we can notice that that there are two degree of freedom making this problem 2D DP
- We will need 2 variable, 1 representing suffix sum & second represent the operation (buy/sell)
- Representation:
- :
- :
- NOTE: purchase can be represented as negative profit.
- but here there is no way to solve ? We will need to write another recurrence for it
- We will have two arrays tracking
n(buy)
: all suffix arraysn(sell)
: all prefix arrays
int maxProfit(vector<int>& prices, int fee) {
int n = prices.size();
vector<vector<int>> dp(n,vector<int>(2,0));
// base case
// 0-> sell
// 1-> buy
dp[n-1][0] = prices[n-1] - fee;
dp[n-1][1] = max(0,-prices[n-1]);
for(int i = n-2; i >= 0; i--){
dp[i][0] = max(prices[i] - fee + dp[i+1][1] , dp[i+1][0]);
dp[i][1] = max(dp[i+1][1], -prices[i]+dp[i+1][0]);
}
return dp[0][1];
}
Longest Arithmetic Subsequenceπ
- Nested, 2D DP
- Problem Link
- Modelling the Problem: We have to find , where : length or largest Arithmetic Subsequence ending at
- Now to find : Assume for every s.t. common difference
d = A[i] - A[j]
is same. - Notice how this requires us to track common difference as well, converting this problem into a 2 DP Problem
- Dimensions - Prefix Array, Common Difference
- Data Structure -> use
unordered_map<int,int>
: key -> cd , value -> length of longest chain.
int longestArithSeqLength(vector<int>& A) {
int n = A.size(), i, j, cd, res = 0;
vector<unordered_map < int, int >> dp(n);
for(i = 0; i < n; i++){
// compute dp[i]
for(j = 0; j < i; j++){
cd = A[i] - A[j];
if(dp[j].find(cd) == dp[j].end())
dp[i][cd] = 2;
else
dp[i][cd] = 1+dp[j][cd];
res = max(res,dp[i][cd]); }
} return res; }
Above gives TLE : one quick fix is the line after calculating cd , second way using a vector of 1000 size because its possible to get small common difference .
Maps were giving TLE because , maps are not always O(1) , instead its average case performance.
int longestArithSeqLength(vector<int>& A) {
int n = A.size(), i, j, cd, res = 0;
vector<vector<int>> dp(n, vector<int> (1001,0));
for(i = 0; i< n; i++){
// compute dp[i]
for(j = 0; j < i; j++){
cd = A[i] - A[j];
dp[i][cd+500] = max(2,1+dp[j][cd+500]);
res = max(res,dp[i][cd+500]);
}
} return res;
}
Target Sumπ
- Problem Link
- Subset DP, 2 D DP, Counting Problem
- DnC Criteria : Split the set into 2 components, set contains the sum with in positive sign while another set with in negative sign
-
: number of ways to make
target-A[0]
fromA[1...n]
-
: number of ways to make
target+A[0]
fromA[1...n]
-
: number of ways to make
- Recurrence :
- Size of DP Array :
- To understand the order of filling the table, try to put some value on above recurrence
- Base Case :
n-1
row where the1
wheretarget == A[n-1]
otherwise0
, or using n
int findTargetSumWays(vector<int>& nums, int target) {
int n = nums.size(), i, j;
vector<vector<int>> dp(n+1, vector<int> (2001,0));
// sum = 0
// -1000 to 1000 => [0,2000]
// 0 to 1000
dp[n][1000] = 1;
for(i = n-1; i >= 0; i--){
for( j = -1000; j <= 1000; j++){
// two cases
// +ve sign
if(j+1000-nums[i] >= 0)
dp[i][j+1000] += dp[i+1][j+1000-nums[i]];
// -ve sign
if(j+1000+nums[i] <= 2000)
dp[i][j+1000] += dp[i+1][j+1000+nums[i]];
}
} return dp[0][target+1000];
}
- A further state space optimization is possible here by using a 2x(2001) size array
Edit Distanceπ
- Problem Link
- Famous Problem Commonly Asked in Interviews
- Here,
dp[i][j]
refers to minimum operation needed to converts1[0...i]
intos2[0...j]
- Given the operations
- If
s1[i] == s2[j]
thendp[i][j] = dp[i-1][j-1]
- If
s1[i] != s2[j]
dp[i][j] = dp[i-1][j-1] + 1
: replace operationdp[i][j] = dp[i][j-1]+1
: insertion operationdp[i][j] = dp[i-1][j]+1
: delete operationdp[i][j]
is minimum of above operation.
- If
- order of filling from top to down and left to right
- Base Case : to transform [a] into [abβ¦.] if there is a in second word then deletion otherwise . Simpler base case is by shifting everything by one. :)
- we add a row above the table and column of left side too. just to make the base case simpler.
int minDistance(string word1, string word2) {
int m = word1.length(),n = word2.length(),i,j;
vector<vector<int>> dp(m+1, vector<int> (n+1,0));
// base cases
for(i = 0 ; i <= n ; i++) dp[0][i] = i;
for(j = 0 ; j <= m ; j++) dp[j][0] = j;
// actual DP implemenation
for(int i = 1 ; i <= m ; i++)
for(int j = 1 ; j<= n ; j++)
if(word1[i-1] == word2[j-1])
dp[i][j] = dp[i-1][j-1];
else
dp[i][j] = 1 + min({dp[i-1][j], dp[i][j-1], dp[i-1][j-1]});
return dp[m][n];
}