Grid DPπ
Minimum Path Sumπ
- Problem Link
- Direction Constraint : down, right only
- We have to minimize the sum along a valid path from
(0,0)
to(m-1, n-1)
- Split criteria: Two sets of problems, where we can either take the down or right cell
- : Min. Path Sum given first step is right step, then solving problem for
- : Min. Path Sum given first step is right step, then solving problem for
- All matrices are suffix matrix for the original matrix
- Recurrence:
- Its a two dimensional DP,
- Base Cases : declare extra column & row with the value
INT_MAX
- Order to fill the table, bottom to top & right to left
int minPathSum(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[0].size() ,i ,j ;
vector< vector<int>> dp(m+1,vector<int>(n+1,INT_MAX));
dp[m][n-1] = dp[m-1][n] = 0;
// bottom to top , R to L
for(i = m-1; i>=0; i--)
for(j = n-1; j>=0; j--)
dp[i][j] = grid[i][j] + min(dp[i+1][j],dp[i][j+1]);
return dp[0][0];
}
Space State Optimization
int minPathSum(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[0].size() ,i ,j ;
vector<int> dp(n+1,INT_MAX);
dp[n-1] = 0;
// bottom to top , R to L
for(i = m-1; i>=0; i--)
for(j = n-1; j>=0; j--)
dp[j] = grid[i][j] + min(dp[j+1],dp[j]);
return dp[0];
}
Dungeon Gameπ
- Problem Link
- Find a path where the health of knight doesnβt go below zero,
- Split Criteria
-
: Initial min. Health of knight for rescuing in the box
(0, 1)
to(m-1, n-1)
-
: Initial min. Health of knight for rescuing in the box
(1, 0)
to(m-1, n-1)
-
: Initial min. Health of knight for rescuing in the box
- By definition & , so
dp[0][0] = val
, so both subproblems will becomeH1
is-6
&H2
is-5
, assuming initial health asval-6
andval-5
respectively, and it is guaranteed that one path will lead to solution by problem constraint - Base Case
- bottom row :
- right column :
- Order of filling : B to L & R to L
int calculateMinimumHP(vector<vector<int>>& dungeon) {
int m = dungeon.size(), n = dungeon[0].size(), i , j;
vector<vector<int>> dp(m,vector<int> (n,INT_MAX));
dp[m-1][n-1] = max(1-dungeon[m-1][n-1],1);
for( i = m-1; i >= 0; i--){
for(j = n-1; j >= 0; j--){
if(i+1 < m)
dp[i][j] = min(dp[i][j],
dp[i+1][j] - dungeon[i][j]);
if(j+1 < n)
dp[i][j] = min(dp[i][j],
dp[i][j+1] - dungeon[i][j]);
dp[i][j] = max(1,dp[i][j]);
}
}
return dp[0][0];
}
Unique Pathsπ
- https://leetcode.com/problems/unique-paths/description/
Frog Jumpπ
- Problem Link
- Split Criteria: at each step we could jump to
k
,k+1
,k-1
- Representation : : can we reach the last stone starting from assuming the last jump made was
k
- Recurrence :
- where , , , s : represents the indices
- Size : nxn, max possible jump is
n+1
, order of filling : bottom to top
TLE Solution
bool canCross(vector<int>& stones) {
if(stones[1]!=1)
return false;
int n = stones.size(), i ,j;
unordered_map<int,int> m;
vector<vector<bool>> dp(n,vector<bool>(n+1,false));
// populate the map
for(i = 0; i <n; i++){
m[stones[i]] = i;
dp[n-1][i+1] = true;
}
// DP table
for(i = n-2; i >= 1; i--){
for(j = 1; j <= n; j++){
// 3 casese
if(j > 1 && m.find(stones[i]+j-1) != m.end())
dp[i][j] = dp[i][j] || dp[m[stones[i]+j-1]][j-1];
// j
if(m.find(stones[i]+j) != m.end())
dp[i][j] = dp[i][j] || dp[m[stones[i]+j]][j];
// j+1
if(m.find(stones[i]+j+1) != m.end())
dp[i][j] = dp[i][j] || dp[m[stones[i]+j+1]][j+1];
}
}
return dp[1][1];
}
- Above solution can be improved by observing that for all the
k
stones we donβt need to store last possible sum - we need only few
k
values: - Bottom Up -> always computing all subproblems, Top-Down -> computes only the needed subproblem
Top-Down Solution Passes
bool canCrossHelper(unordered_map<int,int>& m, vector<vector<int>> &dp ,int i, int j , vector<int>& stones){
int n = stones.size();
// base case
if( i == n-1) return true;
// dp step
if(dp[i][j]!= -1) return dp[i][j];
int t1 = 0, t2=0, t3 = 0;
// 3 casese
if(j > 1 && m.find(stones[i]+j-1) != m.end())
t1 = canCrossHelper(m,dp,m[stones[i]+j-1],j-1,stones);
// j
if(m.find(stones[i]+j) != m.end())
t2 = canCrossHelper(m,dp,m[stones[i]+j],j,stones);
// j+1
if(m.find(stones[i]+j+1) != m.end())
t3 = canCrossHelper(m,dp,m[stones[i]+j+1],j+1,stones);
dp[i][j] = t1 || t2 || t3;
return dp[i][j];
}
bool canCross(vector<int>& stones) {
if(stones[1]!=1)
return false;
int n = stones.size(), i ,j;
unordered_map<int,int> m;
vector<vector<int>> dp(n,vector<int>(n+1,-1));
// populate the map
for(i = 0; i <n; i++){
m[stones[i]] = i;
}
return canCrossHelper(m,dp,1,1,stones);
}
Palindrome DPπ
Longest Palindromic Subsequencesπ
- Problem Link
- Check Stone Game Problem : Link
- Hint : Recurrence :
- Equal :
- Not Equal :
int longestPalindromeSubseq(string s) {
int n = s.size(), len, i;
vector<vector<int>> dp(n,vector<int>(n,0));
// length wise
for(len = 1; len <= n; len++)
for(i = 0; i+len-1 < n; i++)
if(len == 1)
dp[i][i] = 1;
else {
// s[i][i+len-1]
if(s[i] == s[i+len-1])
dp[i][i+len-1] = 2+(i+1> i+len-2?0:dp[i+1][i+len-2]);
else
dp[i][i+len-1] = max(dp[i+1][i+len-1],dp[i][i+len-2]);
}
return dp[0][n-1];
}