Maximum Amount of Money Robot Can Earn

Medium
Watch on YouTube ↗

Solution

/****************************Recursive DP Solution ******************************/
class Solution {
    int m, n;
    Integer dp[][][];
    public int maximumAmount(int[][] coins) {
        this.m = coins.length;
        this.n = coins[0].length;

        dp = new Integer[m][n][3]; // 0,1,2

        return helper(coins, 0, 0, 2);
    }

    int helper(int[][] coins, int i, int j, int skips) {
        // base case
        if(i>=m || j>=n)
            return Integer.MIN_VALUE; // invalid path

        if(dp[i][j][skips]!=null)
            return dp[i][j][skips];
        // last cell
        if(i==m-1 && j==n-1) {
            if(coins[i][j] < 0 && skips>0)
                return 0;
            return coins[i][j];
        }

        // right
        int right = helper(coins, i, j+1, skips);
        
        // down
        int down = helper(coins, i+1, j, skips);

        // skip
        int skip = Integer.MIN_VALUE;

        if(coins[i][j] < 0 && skips>0) {
            int downskip = helper(coins, i+1, j, skips-1);
            int rightskip = helper(coins, i, j+1, skips-1);
            skip = Math.max(downskip, rightskip);
        }

        int maxcoins = Math.max(Math.max(down, right)+coins[i][j],
        skip);

        return dp[i][j][skips] = maxcoins;
    }
}

/***********************Iterative DP Solution****************************** */
class Solution {
    int m, n;
    int dp[][][];
    public int maximumAmount(int[][] coins) {
        this.m = coins.length;
        this.n = coins[0].length;

        dp = new int[m+1][n+1][3]; // 0,1,2
        // initialize
        for(int i=0; i<=m; i++) {
            dp[i][n][0] = Integer.MIN_VALUE;
            dp[i][n][1] = Integer.MIN_VALUE;
            dp[i][n][2] = Integer.MIN_VALUE;
        }
        for(int j=0; j<=n; j++) {
            dp[m][j][0] = Integer.MIN_VALUE;
            dp[m][j][1] = Integer.MIN_VALUE;
            dp[m][j][2] = Integer.MIN_VALUE;
        }

        // dp[i][j][k] = from cell[i,j] to last cell , k skips = max coins
        // dp[m-1][n-1][k] = base case
        // dp[0][0][2] = ans

        for(int i=m-1; i>=0; i--) {
            for(int j=n-1; j>=0; j--) {
                for(int k=0; k<3; k++) {
                    // base case
                    if(i==m-1 && j==n-1) {
                        if(coins[i][j] < 0 && k>0) 
                            dp[i][j][k] = 0;
                        else dp[i][j][k] = coins[i][j];
                    }
                    else {
                        int down = dp[i+1][j][k];
                        int right = dp[i][j+1][k];
                        int skip = Integer.MIN_VALUE;
                        if(coins[i][j] < 0 && k>0) {
                            int downskip = dp[i+1][j][k-1];
                            int rightskip = dp[i][j+1][k-1];
                            skip = Math.max(downskip, rightskip);
                        }
                        dp[i][j][k] = Math.max(Math.max(down, right)+coins[i][j], skip);
                    }
                }
            }
        }

        return dp[0][0][2];
    }
}