3 approaches | Recursion -> Memoization (Top Down) -> Tabulation (Bottom Up) | RunTime Beats 100%
Code (Recursive)Code (Memoization) -577/578 Test cases Passed and 1 Test cases giving TLECode (Tabulation) - (All test cases passed 578/578) & Runtime 84 ms Bea
# Code (Recursive)
```java []
class Solution {
    // RECURSIVE solution (will give TLE)
    // method gives us the maximumAmount if we start at a certain row and col with 2 neutralizers
    private int maximumAmountRecursive(int row, int col, int neutralizers, int[][] coins){
        // out of bounds check
        if(row >= coins.length || col >= coins[0].length)
            return Integer.MIN_VALUE;

        // bottom right corner reached
        if(row == coins.length - 1 && col == coins[0].length - 1)
            return coins[row][col];

        int coinsAtCurrCell = coins[row][col];

        // option 1 : don't neutralize
        int dontNeutralize = coinsAtCurrCell + 
            Math.max(
                maximumAmountRecursive(row, col + 1, neutralizers, coins), // move right
                maximumAmountRecursive(row + 1, col, neutralizers, coins)  // move down
                );

        // option 2 : neutralize (if possible)
        int neutralize = Integer.MIN_VALUE;
        if(coinsAtCurrCell < 0 && neutralizers > 0){
            neutralize = Math.max(
                maximumAmountRecursive(row, col + 1, neutralizers - 1, coins), // move right
                maximumAmountRecursive(row + 1, col, neutralizers - 1, coins)  // move down
                );
        }

        return Math.max(dontNeutralize, neutralize);
    }

    public int maximumAmount(int[][] coins) {
        // at every point the robot has a choice to either go right or down
        // also it can neutralize atmost 2 robbers i.e. 2 neutralizations allowed
        int neutralizers = 2; // given in question

        // RECURSIVE
        return maximumAmountRecursive(0, 0, 2, coins);
    }
}
```

# Code (Memoization) - 
577/578 Test cases Passed and 1 Test cases giving TLE
```java []
class Solution {
    // MEMO solution
    // method gives us the maximumAmount if we start at a certain row and col with 2 neutralizers
    private int maximumAmountMemo(int row, int col, int neutralizers, int[][] coins, int [][][] dp){
        // out of bounds check
        if(row >= coins.length || col >= coins[0].length)
            return Integer.MIN_VALUE;

        int coinsAtCurrCell = coins[row][col];

        // bottom right corner reached
        if(row == coins.length - 1 && col == coins[0].length - 1){
            return dp[row][col][neutralizers] = (coinsAtCurrCell < 0 && neutralizers > 0) ? 0 : coinsAtCurrCell;
        }
            
        if(dp[row][col][neutralizers] != -1)
            return dp[row][col][neutralizers];

        // option 1 : don't neutralize
        int dontNeutralize = coinsAtCurrCell + 
            Math.max(
                maximumAmountMemo(row, col + 1, neutralizers, coins, dp), // move right
                maximumAmountMemo(row + 1, col, neutralizers, coins, dp)  // move down
                );

        // option 2 : neutralize (if possible)
        int neutralize = Integer.MIN_VALUE;
        if(coinsAtCurrCell < 0 && neutralizers > 0){
            neutralize = Math.max(
                maximumAmountMemo(row, col + 1, neutralizers - 1, coins, dp), // move right
                maximumAmountMemo(row + 1, col, neutralizers - 1, coins, dp)  // move down
                );
        }

        return dp[row][col][neutralizers] = Math.max(dontNeutralize, neutralize);
    }

    public int maximumAmount(int[][] coins) {
        // at every point the robot has a choice to either go right or down
        // also it can neutralize atmost 2 robbers i.e. 2 neutralizations allowed
        int neutralizers = 2; // given in question

        // MEMO
        int m = coins.length;
        int n = coins[0].length;

        // size = m * n * (neutralizers + 1) i.e m * n * 3
        int dp[][][] = new int[m][n][neutralizers + 1];

        // initialize all values to -1
        for(int arr1 [][] : dp){
            for(int arr2 [] : arr1){
                Arrays.fill(arr2, -1);
            }
        }

        return maximumAmountMemo(0, 0, neutralizers, coins, dp);
    }
}
```

# Code (Tabulation) - (All test cases passed 578/578) & Runtime 84 ms Beats 78.11% & Memory 79.60 MB Beats 57.29%

```java []
class Solution {
    // Tabulation solution
    private int maximumAmountTabulation(int maxNeutralizers, int m, int n, int[][] coins){
        // size = m * n * (neutralizers + 1) i.e m * n * 3
        int dp[][][] = new int[m][n][maxNeutralizers + 1];

        // incorporated in the dontNeutralize and neutralize cases
        // out of bounds check
        // if(row >= coins.length || col >= coins[0].length)
        //     return Integer.MIN_VALUE;

        // bottom right corner reached
        // if(row == coins.length - 1 && col == coins[0].length - 1){
        //     dp[row][col][neutralizers] = (coinsAtCurrCell < 0 && neutralizers > 0) ? 0 : coinsAtCurrCell;
        // }
        for(int neutralizers = maxNeutralizers; neutralizers >= 0; neutralizers--){
            int coinsAtCurrCell = coins[m - 1][n - 1];
            dp[m - 1][n - 1][neutralizers] = (coinsAtCurrCell < 0 && neutralizers > 0) ? 0 : coinsAtCurrCell;
        }

        for(int row = m - 1; row >= 0; row--){
            for(int col = n - 1; col >= 0; col--){
                int coinsAtCurrCell = coins[row][col];
                for(int neutralizers = maxNeutralizers; neutralizers >= 0; neutralizers--){
                    // base case already covered, so skip
                    if(row == m - 1 && col == n - 1)
                        continue;
                    
                    // option 1 : don't neutralize
                    int dontNeutralize = coinsAtCurrCell + 
                        Math.max(
                            (col + 1 < n ? dp[row][col + 1][neutralizers] : Integer.MIN_VALUE), // move right
                            (row + 1 < m ? dp[row + 1][col][neutralizers] : Integer.MIN_VALUE) // move down
                            );

                    // option 2 : neutralize (if possible)
                    int neutralize = Integer.MIN_VALUE;
                    if(coinsAtCurrCell < 0 && neutralizers > 0){
                        neutralize = Math.max(
                            (col + 1 < n ? dp[row][col + 1][neutralizers - 1] : Integer.MIN_VALUE), // move right
                            (row + 1 < m ? dp[row + 1][col][neutralizers - 1] : Integer.MIN_VALUE) // move down
                            );
                    }

                    dp[row][col][neutralizers] = Math.max(dontNeutralize, neutralize);
                }
            }
        }

        return dp[0][0][maxNeutralizers];
    }

    public int maximumAmount(int[][] coins) {
        // at every point the robot has a choice to either go right or down
        // also it can neutralize atmost 2 robbers i.e. 2 neutralizations allowed
        int neutralizers = 2; // given in question
        int m = coins.length;
        int n = coins[0].length;

        // TABULATION
        return maximumAmountTabulation(neutralizers, m, n, coins);
    }
}
```
['Dynamic Programming', 'Recursion', 'Memoization', 'Java']