Showing posts with label dp. Show all posts
Showing posts with label dp. Show all posts

GCD of all of the subarrays

In this post, I'm going to explain about a question which I came across on quora. The question asks us to calculate gcd of all of the subarrays. If you don;t know what subarray is visit here.
Suppose A = [1, 2, 3, 4, 5] then subarrays are: [1], [2], [3], [4], [5], [1, 2], [2, 3], [3, 4], [4, 5], [1, 2, 3], [2, 3, 4], [3, 4, 5], [1, 2, 3, 4], [2, 3, 4, 5] [1, 2, 3, 4, 5].
Our objective is to find gcd of all of these subarrays. Assume gcd of subarray of length 1 as the element itself. I'll be implementing the solution in Python.

1. Bruteforce
The naive approach would be generating all the subarrays and then finding gcd for each subarray. This idea can be broken down into 2 parts:
  • Finding subarrays
  • Finding GCD of each subarray Let's see how we can find all the subarrays:
def generate_subarray(A):
 """
     function that  generate and returns all subarrays
 """
 ans = []
 # Starting from index i = 0
 # Find subarrays of length 1, 2, 3, ,4 ... starting from i
 for i in range(len(A)):
     for j in range(i + 1, len(A) + 1):
         ans.append(A[i:j])
 return ans
Let's implement a function to find gcd of 2 numbers:

def gcd(a, b):
    if b == 0:
        return a
    return gcd(b, a % b)
Now, let's write a function to find gcd of each of the subarrays.
def find_gcd(sub_array):
    """
        Returns gcd of a sub_array
    """ 
    gcd_sub_array = sub_array[0]

    for i in range(1, len(sub_array)):
        gcd_sub_array = gcd(sub_array[i], gcd_sub_array) 

    return gcd_sub_array
Here is our complete code.
# Dictionary to store subarrays with their GCD
gcd_sub = dict()

def generate_subarray(A):
    """
        function that  generate and returns all subarrays
    """
    ans = []
    # Starting from index i = 0
    # Find subarrays of length 1, 2, 3, ,4 ... starting from i
    for i in range(len(A)):
        for j in range(i + 1, len(A) + 1):
            ans.append(A[i:j])
    return ans

def gcd(a, b):
    if b == 0:
        return a
    return gcd(b, a % b)

def find_gcd(sub_array):
    """
        Returns gcd of a sub_array
    """ 
    gcd_sub_array = sub_array[0]

    for i in range(1, len(sub_array)):
        gcd_sub_array = gcd(sub_array[i], gcd_sub_array) 

    return gcd_sub_array

def main():
    A = [7, 3, 12, 7, 2]
    sub_arrays = generate_subarray(A)

    for sub_array in sub_arrays:
        # For every subarray of length greater than 1
        if len(sub_array) > 1:
            gcd_sub[tuple(sub_array)] = find_gcd(sub_array)
    # Prints
    # {(7, 3): 1, (7, 3, 12): 1, (7, 3, 12, 7): 1, (7, 3, 12, 7, 2): 1, (3, 12): 3, (3, 12, 7): 1, (3, 12, 7, 2): 1, (12, 7): 1, (12, 7, 2): 1, (7, 2): 1}
    print(gcd_sub)


if __name__ == "__main__":
    main()
Can we do better?

2. Tabulation
Let's recall
Suppose A = [1, 2, 3, 4, 5] then subarrays are: [1], [2], [3], [4], [5], [1, 2], [2, 3], [3, 4], [4, 5], [1, 2, 3], [2, 3, 4], [3, 4, 5], [1, 2, 3, 4], [2, 3, 4, 5] [1, 2, 3, 4, 5].
Let's take the subarray [1, 2]. We can see that it can be constructed from subarray [1] by appending 2. Similarly, let's take subarray [2, 3, 4]. We can see that it can be constructed from subarray [2, 3] by appending 4 to it(or [3, 4] by prepending 2 to it) An important observation we can see is that subarray of length j can be constructed simply by appending an element to it if we already have subarray of length j - 1. The same goes with the gcd for calculating subarray. For instance:
If A = [7, 3, 12, 7, 2] and if we have already calculated gcd for [7, 3] then we can calculate gcd for [7, 3, 12] as gcd( gcd(7, 3), 12). Let's try implementing the solution in the tabular approach:
Let dp[i][j] gives gcd for subarray A[i: j]. Then
 dp[i][j] = gcd(dp[i][j - 1], A[j]) if i != j
            A[i] if i == j
Let’s say we have A = [7, 3, 12, 7, 2]
  • dp[0][0], then dp[0][0] = A[0] = 7 This implies that gcd for subarray [7] is 7
  • dp[0][1], then dp[0][1] = gcd(dp[0][0], A[1]) = gcd(7, 3) = 1 which implies that gcd for subarray [7, 3] is 1
  • dp[0][2], then dp[0][2] = gcd(dp[0][1], A[2]) = gcd(1, 12) = 1 which implies that gcd for subarray [7, 3, 12] is 1
  • dp[0][3], then dp[0][3] = gcd(dp[0][2], A[3]) = gcd(1, 7) = 1 which implies that gcd for subarray [7, 3, 12, 7] is 1
  • dp[0][4], then dp[0][4] = gcd(dp[0][3], A[4]) = gcd(1, 2) = 1 which implies that gcd for subarray [7, 3, 12, 7, 2] is 1
  • dp[1][1], then dp[1][1] = A[1] = 3
and so on..
Here is the complete code.
gcd_sub = dict()

def gcd(a, b):
    if b == 0:
        return a
    return gcd(b, a % b)


def main():
    A = [7, 3, 12, 7, 2]
    # Construct 2D array of size len(A) by len(A)
    # and initialize with -1
    dp = [[-1 for _ in range(len(A))] for _ in range(len(A))]

    # Set GCD of single element as the element itself
    for i in range(len(A)):
        dp[i][i] = A[i]

    # For every other subarrays of length l
    # Calculate gcd using  length l - 1
    for i in range(0, len(A)):
        for j in range(i + 1, len(A)):
            # print(A[i:j], A[j])
            dp[i][j] = gcd(dp[i][j - 1], A[j])
            gcd_sub[tuple(A[i: j + 1])] = dp[i][j]

    print(gcd_sub)

if __name__ == "__main__":
    main()
Share:

DP: Longest Increasing Subsequence

The Longest Increasing Subsequence (LIS) problem is to find the length of the longest subsequence of a given sequence such that all elements of the subsequence are sorted in increasing order.
Note: The subsequence is not necessarily unique or contiguous.

In this post, I'll be solving classic DP problem which involves finding lis of a given array as well as some of its variations.
The problems related to LIS that I'll be seeing are :

Let's see problem 1 and 2. Both the problems are similar. The task is to find the length of the longest increasing(strictly) subsequence.
eg: [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]
 Here length of LIS = 6. 
We can have multiple LIS with maximum length, but in this problem we are not concerned about the number of longest increasing subsequence(which we will see in 3rd problem here).


I'm gonna dive directly into bottom up approach for solving LIS in O(n ^ 2).

Approach:

Let's observe few scenarios.
A = [1 ,2 ,3, 4, 5]
If we have such array, then how can we find LIS upto length 1... 5. We're gonna need some kind of array to store those values. Let's say we make an array of size that of the given array and initialize with 1 as it is guaranteed that the minimum LIS for an array of length greater than 0 is always 1(Case when there is only 1 element)

What will be the approach to find lis upto index i????
Obviously we have to look at index from j = 0 to i - 1 and see if we can improve by taking element at index j such that element A[j] < A[i]

This roughly translates to below snipppet: lis[i] = max(lis[i], 1 + lis[j])
After building the LIS table , we can return the maximum value from the lis array

Implementation

int Solution::lis(const vector<int> &A) {
    // If the array is empty
    if(A.size() == 0){
            return 0;
        }
        // Initialize lis array with 1
        vector<int> lis(A.size(), 1);
        
        for(int i = 0; i < A.size(); i++){
            for(int j = 0; j < i; j++){
                // If jth element can be taken 
                // Maximize lis upto index i
                if(A[j] < A[i]){
                    lis[i] = max(lis[i], 1 + lis[j]);
                }
            }
        }
        return *max_element(lis.begin(), lis.end());
}





Share:

Leetcode 72. Edit Distance

Problem Link : https://leetcode.com/problems/edit-distance/

Given two words word1 and word2, find the minimum number of operations required to convert word1 to word2.
You have the following 3 operations permitted on a word:
  1. Insert a character
  2. Delete a character
  3. Replace a character
Example 1:
Input: word1 = "horse", word2 = "ros"
Output: 3
Explanation: 
horse -> rorse (replace 'h' with 'r')
rorse -> rose (remove 'r')
rose -> ros (remove 'e')
Example 2:
Input: word1 = "intention", word2 = "execution"
Output: 5
Explanation: 
intention -> inention (remove 't')
inention -> enention (replace 'i' with 'e')
enention -> exention (replace 'n' with 'x')
exention -> exection (replace 'n' with 'c')
exection -> execution (insert 'u')

Solution:

Edit distance between two strings is the minimum number of operations required to convert one string to another. We are given two strings word1 and word2 and are asked to calculate minimum number of operations(insert, delete or replace) required to convert word1 to word2.
Let's try to solve this problem recursively with caching/ top down
class Solution {
public:
    
    // Stores precomputed (i, j) i,e cost for s with length i and
    // t with j length
    map<pair<int, int>, int> mp;
    
    string s, t;
    int helper(int i, int j){
        
        // If already computed for length i and j simply return computed value
        if (mp.find({i, j}) != mp.end()){
            return mp[{i, j}];
        }
        
        // If length of the first string is 0
        // Then we need to insert all the characters equal to length of 
        // second string
        // eg: s = "" and t = "ram"
        // Then we need to insert 3 characters "ram" into s
        
        if(i == 0){
            return j;
        }
        
        // If length of second string is 0
        // Then we need to delete 3 characters from first string
        if(j == 0){
            return i;
        }
        
        // If the corresponding ith and jth character matches 
        // we don't need any operations
        // we just solve for (i - 1) length and (j - 1) length of s and t
        // eg: s = "ram" and t = "cram"
        // Here s[2] == t[3]. So we dont need any additional operation
        // We just solve for its smaller instance i.e s becomes "ra" and t becomes "cra"
        if(s[i - 1] == t[j - 1]){
            return helper(i - 1, j - 1);
        }
        
        // Insert 
        // s = "horse", t = "ros"
        // We insert character 's' costing 1 operations
        // "horses" and "ros" i.e we can eliminate matcging characters from last
        // Then problem reduces to "horse" and "ro"
        // i.e length of string s doesn't change but string t reduces by size 1
        int ins = 1 + helper(i , j - 1);
        
        // Replace
        // eg: = "horse", t = "ros"
        // We can replace last character of string s to 's' with 1 cost operation
        // Then we can eliminate matching characters
        // Then problem reduces to "hors" and "ro"
        // i.e length of s reduces by 1 and t reduces by 1
        int rep = 1 + helper(i - 1, j - 1);
        
        // Delete
        // eg: "horse", t = "ros"
        // We can delete last character from string s with cost 1
        // Then problem reduces to "hors" and "ros"
        // i.e length of s reduces by 1 but length of t doesnt change
        int del = 1 + helper(i - 1, j);
        
        // Save the computed result in dictionary
        mp[{i, j}] = min({ins, rep, del});
        return mp[{i, j}];
        
    }
    int minDistance(string word1, string word2) {
       s = word1;
       t = word2;
       return helper(word1.size(), word2.size());
    }
};

Top-Down approach passes the testcases but sometimes may cause stack overhead due to more recursive calls and you may face issues in language like python unless you explicitly set recursion limit.
So let's try translating the code to bottom up dp.
The first thing we can observe is we are interested only in two parameters :

  • length of word1 (i)
  • length of word2 (j)
We can write f(i, j) as dp[i][j] which stores edit distance between two string word1 and word2

Translating the code is straight forward, just replace the function call with dp array states. See the implementation
class Solution {
public:
    int minDistance(string word1, string word2) {
        int n = word1.size();
        int m = word2.size();
        vector<vector<int>> dp(n + 1, vector<int>(m + 1, -1));
        
        for(int i = 0; i <= n; i++){
            dp[i][0] = i;
        }
        
         for(int j = 0; j <= m; j++){
            dp[0][j] = j;
        }
        for(int i = 1; i <= n; i++ ){
            for(int j = 1; j <= m; j++){
                if(word1[i - 1] == word2[j - 1]){
                    dp[i][j] = dp[i - 1][j - 1];
                }
                else{
                    //Insert
                    dp[i][j] = 1 + dp[i][j - 1];
                    //Delete
                    dp[i][j] = min(dp[i][j], 1 + dp[i - 1][j]);
                    //Replace
                    dp[i][j] = min(dp[i][j], 1 + dp[i - 1][j - 1]);
                    
                }
            }
        }
        return dp[n][m];
        
    }
};





Share:

Leetcode 931. Minimum Falling Path Sum

Problem Link: https://leetcode.com/problems/minimum-falling-path-sum/



Given a square array of integers A, we want the minimum sum of a falling path through A.
A falling path starts at any element in the first row, and chooses one element from each row.  The next row's choice must be in a column that is different from the previous row's column by at most one.

Example 1:
Input: [[1,2,3],[4,5,6],[7,8,9]]
Output: 12
Explanation: 
The possible falling paths are:
  • [1,4,7], [1,4,8], [1,5,7], [1,5,8], [1,5,9]
  • [2,4,7], [2,4,8], [2,5,7], [2,5,8], [2,5,9], [2,6,8], [2,6,9]
  • [3,5,7], [3,5,8], [3,5,9], [3,6,8], [3,6,9]
The falling path with the smallest sum is [1,4,7], so the answer is 12.

Note:
  1. 1 <= A.length == A[0].length <= 100
  2. -100 <= A[i][j] <= 100

Solution:

We are given a square grid of size n * n.
What we want is the minimum falling path sum. ie. the minimum sum while falling through row 0 to row (n - 1)
The constraints in the problem is while falling from column of ith row to (i + 1)th row, we can fall on either of the columns {j - 1, j , j+ 1} as it is mentioned that the choice of next row must be in a column that is different from the previous row's column by at most one.


Similar to other grid dp problems, I'm gonna start with the case when I'm at (i, j) cell. How can I reach (i, j) cell??
We can reach (i, j) cell from either of (i - 1, j - 1), (i - 1, j) or (i - 1, j - 1) cell.


Let dp[i][j] gives the minimum possible falling path sum. Then
 dp[i][j] = A[i][j] + min(dp[i - 1][j - 1], dp[i - 1][j], dp[i - 1][j - 1]) 
We must consider a special case for the first row(0th). There is no way to fall to 0th row so, minimum falling path cost is given by the weight of the cell itself
 dp[0][i] = A[0][i] 
Now we are almost done with the solution , for every cell(i, j) form(1, 0) to (n - 1, n- 1) we fill up the dp table in bottom up manner. See the implementation .


Implementation: 

class Solution {
public:
    int minFallingPathSum(vector<vector<int>>& A) {
        
        // Size of grid
        int n = A.size();
        
        // dp[i][j] gives the minimum sum of falling path for cell(i, j)
        vector<vector<int>> dp(n, vector<int> (n, INT_MAX));
        
        // For cell at 0th row we can't fall from any row
        // So for all cells at 0th row minimum sum of falling is the
        // value of eleement itself
        for(int i = 0; i < n; i++){
            dp[0][i] = A[0][i];
        }
        
        
        // Suppose our ans is infinite
        int ans = INT_MAX;
        
        // For all rows from 1 to n - 1
        // We can fall to cell (i, j) from (i - 1, j - 1) or (i - 1, j) or (i - 1, j          + 1)
        
        for(int i  = 1; i < n; i++){
            for(int j = 0; j < n; j++){
                
                // if cell(i, j) is not of last column
                // we can fall from previous row (i - 1, j + 1) with
                //  column greater than 1
                if(j + 1 < n){
                   dp[i][j] =   min(dp[i][j], dp[i - 1][j + 1]);
                }
                // if cell(i, j) is not of first column
                // we can fall from previous row (i - 1, j - 1) with
                //  column less than 1
                if(j - 1 >= 0){
                     dp[i][j] =  min(dp[i][j], dp[i - 1][j - 1]);
                }
                
                // Otherwise we can fall directly from the cell above it(i - 1, j -                 1)
                dp[i][j] =  min(dp[i][j] , dp[i - 1][j]);
                
                // Cost of falling is minimum of the paths and current value of the cell (i, j)
                dp[i][j] += A[i][j];
                
            }
        }
        
        
        // Loop through all elements at last row and compute the minimum value
        // which is the minimum sum of a falling path
        for(auto x: dp[n - 1]){
            ans = min(ans, x);
        }
        return ans;
    }  
};



Share:

Leetcode 198. House Robber

Problem Link https://leetcode.com/problems/house-robber/

You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.
Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.
Example 1:
Input: [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
             Total amount you can rob = 1 + 3 = 4.
Example 2:
Input: [2,7,9,3,1]
Output: 12
Explanation: Rob house 1 (money = 2), rob house 3 (money = 9) and rob house 5 (money = 1).
             Total amount you can rob = 2 + 9 + 1 = 12.
Solution:
We are given integers representing the amount of money at ith house. Our task is to maximize the total money. The constraint is that we are not allowed to rob two consecutive houses.
Let's say we rob 0th house then we can't rob 1st house.

I'll be solving this problem using bottom-up dp.
Suppose dp[i] is the total maximum amount of money that we can rob till ith house.
Clearly:
 dp[0] = nums[0] 
as the total amount of money, we can rob till house 0 is what is in house 0 itself. Also, we can see that the total maximum amount we can rob till house 1st is
 dp[1] = max(nums[0], nums[1]) 
which means we rob either of the house 0 or 1 which has the maxim value.


For all other houses i , we can have maximum  if we don't rob the current house and rob (i - 1)th house or rob ith house with value nums[i]
 dp[i] = max(dp[i - 1], nums[i] +  dp[i - 2]); 



Implementation:
class Solution {
public:
    int rob(vector& nums) {
        // If there is no house
        //  Maximum sum that we can rob is 0
        if(nums.size() == 0){
            return 0;
        }
        
        // If there is only 1 house maximum money is \
        // by robbing the only house
        if(nums.size() == 1){
            return nums[0];
        }
        
        // If there are 2 houses we can rob one of the houses
        // But not both of them as they are consecutive
        // So we maximize the robbery by chossing the house with maximum value
        if(nums.size() == 2){
            return max(nums[0], nums[1]);
        }
        
        // dp[i] stores the maximum value that we can rob till ith house
        vector dp(nums.size(), 0);
        
        // Base Cases
        dp[0] = nums[0];
        dp[1] = max(nums[0], nums[1]);
        
        // For all houses from i = 2 to n - 1
        // Either rob the ith house giving maxm value = nums[i] + dp[i - 2]
        // Or dont rob ith house by giving maximum vale = d[i - 1]
        // We choose the maximum of these two values
        for(int i = 2; i < nums.size(); i++){
            dp[i] = max(dp[i - 1], nums[i] +  dp[i - 2]);
        }
        
        // return maximum value we can rob till (n - 1)th house
        return dp[nums.size() - 1];
    }
};

Share:

Leetcode 63. Unique Paths II

Problem Link: https://leetcode.com/problems/unique-paths-ii/


A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below).
The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below).
Now consider if some obstacles are added to the grids. How many unique paths would there be?
An obstacle and empty space is marked as 1 and 0 respectively in the grid.
Note: m and n will be at most 100.

Example 1:
Input:
[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]
Output: 2
Explanation:
There is one obstacle in the middle of the 3x3 grid above.
There are two ways to reach the bottom-right corner:
1. Right -> Right -> Down -> Down
2. Down -> Down -> Right -> Right

Solution:

Suppose we are at any cell (i, j). Then, the number of ways to reach the cell (i, j) is the sum of number of ways to reach cell (i - 1, j) (above) and (i, j - 1) (left) i.e
          numways(i, j) = numways(i - 1, j) + numways(i, j - 1) 

Instead of using the recursive approach I'm gonna use bottom-up dp to solve the problem.
Let's say dp[i][j] gives the number of ways to reach cell (i, j).
Then,
          dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
The added constraints in the problem is that any cell(i, j) can be either 1 or 0 where 1 denotes there is an obstacle. Clearly
  if(obstacleGrid[i][j] == 1){
                    dp[i][j] = 0;
                }
                else{
                    dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
             }
This is because if the cell(i, j) has obstacle then there is no way we can reach cell (i, j)
We have to handle the base case when the cell is of size 1 * 1. If the cell at (0, 0) has obstacle then there is no way we can reach cell(0, 0) . So we immediately return 0. Else we return 1 as there is only 1 way in tbis case
  if(m == 1 && n == 1){
             if(obstacleGrid[0][0] == 1){
                 return 0;
            }
            return 1;
        }
Let's see the first row and first column.
What is the number of ways to reach any cell (i, 0) or (0, j) ???
There is only one way to reach cell (i, 0) i.e only from upward direction i.e cell (i - 1, 0).
So,
          dp[i][0] = dp[i - 1][j]
Similarly, there is only one way to reach cell (0, j) i.e only from left direction i.e cell (0, j - 1).
So,


          dp[0][j] = dp[0][j - 1]
Using the added constraints in the problem we can rewrite these two conditions as:
We can write the code for first column as
if(obstacleGrid[i][0] == 1){
                dp[i][0] = 0;
}
else if(i < 1){
                dp[i][0] = 1;
}
else{
                dp[i][0] = dp[i - 1][0];
}
Similarly for first row:
if(obstacleGrid[i][0] == 1){
                dp[i][0] = 0;
}
else if(i < 1){
                dp[i][0] = 1;
}
else{
                dp[i][0] = dp[i - 1][0];
}




Implementation:

 class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
     
     
     // FInd number of rows
        int m = obstacleGrid.size();
        
        // Find number of columns 
        int n = obstacleGrid[0].size();
        
        // dp[i][j] gives the num of ways to reach cell(i, j)
        // Initialise 2d array of size m * n with 0
        vector<vector<long long>> dp(m, vector<long long> (n, 0));
        
        // Base condition: If there is only 1 cell
        if(m == 1 && n == 1){
             if(obstacleGrid[0][0] == 1){
                 return 0;
            }
            return 1;
        }
        
        
        
  
        // First column cell (i, 0) can be reached from cell (i - 1, 0)
        for(int i = 0; i < m; i++){
         // If any cell (i, 0) contains obstacle then there is no way to reach the cell(i, j)
         // so dp[i][0] = 0
            if(obstacleGrid[i][0] == 1){
                dp[i][0] = 0;
            }
            // else if it is the first cell (0, 0) and there is no obstacle then
         // dp[i][0] = 1
            else if(i < 1){
                 dp[i][0] = 1;
            }
            // Otherwise we can reach cell (i, 0) from cell(i - 1, 0)
      // so dp[i][0] = dp[i - 1][0]
            else{
                 dp[i][0] = dp[i - 1][0];
            }
           
        }
        
        // First row cell (0, i) can be reached from cell (0, i - 1)
         for(int i = 0; i < n; i++){
          // If any cell (0, i) contains obstacle then there is no way to reach the cell(0, i)
         // so dp[0][i] = 0
            if(obstacleGrid[0][i] == 1){
                dp[0][i] = 0;
            }
            // else if it is the first cell (0, 0) and there is no obstacle then
         // dp[0][i] = 1
            else if(i < 1){
                 dp[0][i] = 1;
            }
            // Otherwise we can reach cell (0, j) from cell(0, j - 1)
         // so dp[0][i] = dp[0][i - 1]
            else{
                    dp[0][i] = dp[0][i - 1];
            }
        }
        
        
        // For every other cells (1, 1) to (m - 1, n - 1)
        // Build dp table in bottom up manner
        for(int i = 1; i < m; i++){
            for(int j = 1; j < n; j++){
             // If obstacle no way to reach cell(i, j)
             // So dp[i][j] =0 
                if(obstacleGrid[i][j] == 1){
                    dp[i][j] = 0;
                }
                //Else num of ways to reach cell(i, j) is
                // the sum of num of ways to reach cell(i - 1, j) and (i, j - 1)
                else{
                    dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
            }
            }
         
        }

  // return num of ways to reach cell(m - 1, n - 1)      
        return dp[m - 1][n - 1];
    }
};
Here is a slightly simpler version of this problem: https://leetcode.com/problems/unique-paths/
Share:

Leetcode 62: Unique Paths

Problem Link: https://leetcode.com/problems/unique-paths/


A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below).
The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below).
How many possible unique paths are there?
Above is a 7 x 3 grid. How many possible unique paths are there?
Note: m and n will be at most 100.
Example 1:
Input: m = 3, n = 2
Output: 3
Explanation:
From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:
1. Right -> Right -> Down
2. Right -> Down -> Right
3. Down -> Right -> Right
Example 2:
Input: m = 7, n = 3
Output: 28

Solution:

Suppose we are at any cell (i, j). Then ,  the number of ways to reach the cell (i, j) is the sum of number of ways to reach cell (i - 1, j) (above) and (i, j - 1) (left) i.e
          numways(i, j) = numways(i - 1, j) + numways(i, j - 1) 

Instead of using recursive approach I'm gonna use bottom up dp to solve the problem.
Let's say dp[i][j] gives the number of ways to reach cell (i, j).
Then,
          dp[i][j] = dp[i - 1][j] + dp[i][j - 1]

Let's see the first row and first column.
What is the number of ways to reach any cell (i, 0) or (0, j) ???
There is only one way to reach cell (i, 0) i.e only from upward direction i.e cell (i - 1, 0).
So,
          dp[i][0] = 1 
Similarly, there is only one way to reach cell (0, j) i.e only from left direction i.e cell (0, j - 1).
So,
          dp[0][j] = 1 

Implementation:

 class Solution {
public:
    int uniquePaths(int m, int n) {
     
     // dp[i][j]  gives the number of ways to reach cell (i, j)
        int dp[m][n];
        
        // There is only 1 way to reach any cell at first column i.e
        // from the cell upward 
        // So dp[i][0] = 1
        for(int i = 0; i < m; i++){
            dp[i][0] = 1;
        }
        
        
        // There is only 1 way to reach any cell at first row i.e
        // from the cell left 
        // So dp[0][j] = 1
        for(int i = 0; i < n; i++){
            dp[0][i] = 1;
        }
        
        
        // For all cells (i, j) from (1, 1) to (m - 1, n - 1)
        // we build the table in bottom up manner
        // We can reach any cell (i, j) from (i - 1, j) or (i, j - 1)
        // So dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
        for(int i = 1; i < m; i++){
            for(int j = 1; j < n; j++){
                dp[i][j]  = dp[i - 1][j] + dp[i][j - 1];
            }
        }
        
        // Return number of ways to reach cell (m - 1, n - 1)
        return dp[m - 1][n - 1];
        
    }
};
Here is a slightly modified version of this problem: https://leetcode.com/problems/unique-paths-ii/

Share:

Codeforces Round #119 (Div. 2) A. Cut Ribbon

Problem Link
Polycarpus has a ribbon, its length is n. He wants to cut the ribbon in a way that fulfills the following two conditions:
  • After the cutting, each ribbon piece should have length a, b or c.
  • After cutting the number of ribbon pieces should be maximum.
Help Polycarpus and find the number of ribbon pieces after the required cutting.
Input
The first line contains four space-separated integers n, a, b and c (1 ≤ n, a, b, c ≤ 4000) — the length of the original ribbon and the acceptable lengths of the ribbon pieces after the cutting, correspondingly. The numbers a, b and c can coincide.
Output
Print a single number — the maximum possible number of ribbon pieces. It is guaranteed that at least one correct ribbon cutting exists.
Examples
input
5 5 3 2  
output
2  
input
7 5 5 2  
output
2
Note
In the first example, Polycarpus can cut the ribbon in such a way: the first piece has length 2, the second piece has length 3.
In the second example, Polycarpus can cut the ribbon in such a way: the first piece has length 5, the second piece has length 2.
Approach:
We are given a certain ribbon of length n and we are asked to cut the ribbon such that we have maximum pieces where each piece can be of length a, b, or c
Let f (n) be the function that gives the maximum number of pieces that a ribbon of length be cut. Then,
  f(n)  =  1  + max(f(n - a),
                    f(n - b),
                    f(n - c))
The base case is when n becomes 0 which means that it is not possible to cut the ribbon into further pieces
so, f(0) = 0
After, cutting the ribbon of length n we get a similar problem with reduced length(optimal substructure) and many repeating subproblems(try drawing recursion tree for the first test case). This is the characteristics of DP problems. So we can apply DP.
As top-down approach looks more natural let’s first implement this solution.
I’m going to use Python for this problem. The only problem with python is it has a recursion limit. So I’ve to explicitly set recursion limit to some maximum value.
import sys
sys.setrecursionlimit(500000000)
Visualising 2nd Testcase
Let’s dive into our code
#Author: Bishal Sarang
import sys
sys.setrecursionlimit(500000000)

def f(n):
    """
    returns maximum number of pieces that can be cut for ribbon with length n
    """
    
    # If maximum num of pieces for length n is already computed simply return it
    if n in memo.keys():
        return memo[n]
   
    ans = float("-inf")
    if n == 0:
        return 0
    for length in l:
        # Cut into pieces if only we wont have negative length of ribbon
        if n >= length:
            ans = max(ans, 1 + f(n - length))
    #Cache the result
    memo[n] = ans
    return ans
    
#Dict to store computed values
memo = dict()

# Read Input
l = list(map(int, input().split()))
n, l = l[0], l[1:]
print(f(n))
As we have seen the issue with some languages like Python, there is some recursion limit, bottom-up dp seems more convenient.
The solution for bottom of dp is just translating the above approach by building the solution for length 1, length 2, length 3 ....upto length n.
Let dp[n] gives the maximum number of pieces possible for length n such that dp[i] gives the maximum number of pieces possible for length i where 1 <= i <= n.
Initialize an array of length (n + 1) with negative infinity denoting initially all length are not possible.
Base case:
dp[0] = 0
Iteratively build the solution by calculating
dp[i] = max(dp[i],
            1 + dp[i - a],
            1 + dp[i - b],
            1 + dp[i - c])
We can write dp[i] in a more readable format using loop.
for length in l:
    # Cut into pieces if only we dont have negative length of ribbon
    if i - length >= 0:
        dp[i] = max(dp[i], 1 + dp[i - length])
Let’s see the complete bottom-up implementation.
#Author: Bishal Sarang

def f(n):
    # Build maximum number of pieces for
    #length 1 upto n in bottom up manner
    dp = [float("-inf")] * (n + 1)

    # Base Case
    dp[0] = 0

    # dp[i] gives maximum number of pieces that can
    # be obtained by cutting ribbon of length  i into pieces
    # of length a, b or c
    # dp[i] = -inf if it is not possible to cut the ribbon into pieces
    for i in range(1, n + 1):
        for length in l:
            # Cut into pieces if only we dont have negative length of ribbon
            if i - length >= 0:
                dp[i] = max(dp[i], 1 + dp[i - length])
    # return maximum number of pieces possible for ribbon with length n
    return dp[n]

l = list(map(int, input().split()))
n, l = l[0], l[1:]
print(f(n))
Share:

Codeforces Round #345 (Div. 2) A. Joysticks

Friends are going to play console. They have two joysticks and only one charger for them. Initially first joystick is charged at a1 percent and second one is charged at a2 percent. You can connect charger to a joystick only at the beginning of each minute. In one minute joystick either discharges by 2 percent (if not connected to a charger) or charges by 1 percent (if connected to a charger).
Game continues while both joysticks have a positive charge. Hence, if at the beginning of minute some joystick is charged by 1 percent, it has to be connected to a charger, otherwise the game stops. If some joystick completely discharges (its charge turns to 0), the game also stops.
Determine the maximum number of minutes that game can last. It is prohibited to pause the game, i. e. at each moment both joysticks should be enabled. It is allowed for joystick to be charged by more than 100 percent.
Input
The first line of the input contains two positive integers a1 and a2 (1 ≤ a1, a2 ≤ 100), the initial charge level of first and second joystick respectively.
Output
Output the only integer, the maximum number of minutes that the game can last. Game continues until some joystick is discharged.
Examples
input
Copy
3 5
output
Copy
6
input
Copy
4 4
output
Copy
5
Note
In the first sample game lasts for 6 minute by using the following algorithm:
  • at the beginning of the first minute connect first joystick to the charger, by the end of this minute first joystick is at 4%, second is at 3%;
  • continue the game without changing charger, by the end of the second minute the first joystick is at 5%, second is at 1%;
  • at the beginning of the third minute connect second joystick to the charger, after this minute the first joystick is at 3%, the second one is at 2%;
  • continue the game without changing charger, by the end of the fourth minute first joystick is at 1%, second one is at 3%;
  • at the beginning of the fifth minute connect first joystick to the charger, after this minute the first joystick is at 2%, the second one is at 1%;
  • at the beginning of the sixth minute connect second joystick to the charger, after this minute the first joystick is at 0%, the second one is at 2%.
After that the first joystick is completely discharged and the game is stopped.

Solution:

This problem can be solved recursively with caching.
Let's say we are given initial charges of joystick as a and b. 
Let f(a, b) gives the maximum amount of time. Then at any instance we have two options:

  • Charge first joystick i.e a becomes a + 1 and b becomes b - 2. So charge_first = 1 + f(a + 1, b - 2)
  • Charge second joystick i.e a becomes a - 2 and b becomes b + 1. So charge_second= 1 + f(a - 2, b + 1)
Then:
        f(a, b) = max(charge_first, charge_second)
Also, we have to consider two base cases:


  • Charge of either a or b becomes less than or equal to 0.
  • Charge of both the joystick is 1 
For  both the cases there is no way the game can be played. So we return 0

Instead of simply using recursion we use caching to save the states instead of re-calculating it. Particularly we use tuple (a, b) as keys in dictionary


Implementation:




Share:

At Coder Educational DP Contest Frog 2

Problem Link:

https://atcoder.jp/contests/dp/tasks/dp_b

Problem Statement

There are N stones, numbered 1,2,…,N. For each i (1≤i≤N) the height of Stone i is h
There is a frog who is initially on Stone 1. He will repeat the following action some number of times to reach Stone N:
If the frog is currently on Stone i jump to one of the following: Stone i+1,i+2,…,i+K. Here, a cost of |hi−hj| is incurred, where j is the stone to land on.
Find the minimum possible total cost incurred before the frog reaches Stone N.

Constraints

  • All values in input are integers.
  • 2≤N≤105
  • 1≤K≤100
  • 1≤hi≤104

Input

Input is given from Standard Input in the following format:
N K
h1 h2 … hN

Output

Print the minimum possible total cost incurred.
5 3
10 30 40 50 20

Sample Output 1
30
If we follow the path 11 → 22 → 55, the total cost incurred would be |10−30|+|30−20|=30.

Solution:

This problem is similar to Frog A . The only difference is that if the frog is at ith stone, it can jump upto k stones from the current stone.
Let’s say the frog is currently at i = 0 stones and k = 3, in one hop it can jump to one of the {1, 2, 3} stone.
The task is to find the minimum cost to reach (n - 1)th stone (0 based indexing as I find it easier)
Make an array dp[n] and initialize with infinite distance.Here, dp[i] gives the cost to reach ith stone. So,
dp[0] = 0;
dp[1] = abs(h[1] - h[0])
For every other stones 2 <= i < n, the frog can jump from from the stone before it, as long as the distance is less than or equal to k.
for(int j = i - 1, jump = 0; j >= 0 && jump < k; j--, jump++){
     dp[i] = min(dp[i], dp[j] + abs(h[j] - h[i]));
}

Implementation:

#include <bits/stdc++.h>
 
using namespace std;
 
int main(){
    int n, k; cin >> n >> k;
    vector<int> h(n);
    for(int i = 0; i < n; i++){
        cin >> h[i];
    }
    
    //dp[i] denotes the minimum cost to reach ith stone
    // 0 < i < n - 1 are the stones
    //We are asked to dind the cost to reach last stone i.e dp[n - 1]
    //Initially there is infinite cost to reach ith stones
    vector<int> dp(n, INT_MAX);
  
    //To reach first stone there is no cost. SO dp[0] = 0
    dp[0] = 0;
   //To reach second stone the frog can jump from 0th stone costing dp[1] = abs(h[1] - h[0])
    dp[1] = abs(h[1] - h[0]);
    
    //For every other stones 2 <= i < n, the frog can jump from the (i - 1), (i - 2)...(i - k)th stones 
    for(int i = 2; i < n; i++){
      for(int j = i - 1, jump = 0; j  >= 0 && jump < k; j--, jump++){
        dp[i] = min(dp[i], dp[j] + abs(h[j] - h[i]));
      }
    }
    //Print minm cost to reach (n - 1)th stone
    cout << dp[n - 1];
    return 0;
}
Share:

AtCoder Educational DP Contest Frog 1

Problem Link: 
https://atcoder.jp/contests/dp/tasks/dp_a


Problem Statement

There are N stones, numbered 1,2,,N. For each i (1iN), the height of Stone i is hi.
There is a frog who is initially on Stone 1. He will repeat the following action some number of times to reach Stone N:
  • If the frog is currently on Stone i, jump to Stone i+1 or Stone i+2. Here, a cost of |hihj| is incurred, where j is the stone to land on.
Find the minimum possible total cost incurred before the frog reaches Stone N.

Constraints


  • All values in input are integers.
  • 2N105
  • 1hi104

Input


Input is given from Standard Input in the following format:
N
h1 h2  hN

Output


Print the minimum possible total cost incurred.

Sample Input 1 Copy

Copy
4
10 30 40 20
Sample Output 1 Copy

Copy
30
If we follow the path 1 → 2 → 4, the total cost incurred would be |1030|+|3020|=30.
Sample Input 2 Copy

Copy
2
10 10
Sample Output 2 Copy

Copy
0
If we follow the path 1 → 2, the total cost incurred would be |1010|=0.
Sample Input 3 Copy

Copy
6
30 10 60 10 60 50
Sample Output 3 Copy

Copy
40
If we follow the path 1 → 3 → 5 → 6, the total cost incurred would be |3060|+|6060|+|6050|=40.

Solution:

This problem can be solved using dynamic programming.
Let dp[i] be the minimum total cost to reach ith stone.
Then :
dp[i] =  min(dp[i - 2]   + abs(h[i] - h[i - 2] , 
                       dp[i - 1] + abs(h[i] - h[i - 1]]);
For 0th and 1st stones:
  dp[0] = 0;
dp[1] = abs(h[1] - h[0])

Implementation 

Share: