# 120. Triangle

## Problem

{% embed url="<https://leetcode.com/problems/triangle/description/>" %}

## Intuition

<div align="left"><figure><img src="https://1388126071-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVQ7Ie-PZpN_8yApX0-%2Fuploads%2FpyVKtqheUNzFkLKjTNOe%2FPage1.png?alt=media&#x26;token=9907b37d-26b3-4ad1-a042-b1aa6b18533c" alt="" width="375"><figcaption></figcaption></figure> <figure><img src="https://1388126071-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVQ7Ie-PZpN_8yApX0-%2Fuploads%2FuwkCu9dzfg4AD5xv8ina%2FPage2.png?alt=media&#x26;token=3901731f-6a9b-4fcb-9898-345445cf4873" alt="" width="375"><figcaption></figcaption></figure></div>

<div><figure><img src="https://1388126071-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVQ7Ie-PZpN_8yApX0-%2Fuploads%2FEWN0Abu8CfpAx4TymZYb%2FPage3.png?alt=media&#x26;token=460fe079-5dab-4435-b961-a92b65015bdd" alt=""><figcaption></figcaption></figure> <figure><img src="https://1388126071-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVQ7Ie-PZpN_8yApX0-%2Fuploads%2Ftz1z8LR8y0NE7ghctOa7%2FPage4.png?alt=media&#x26;token=b19bc307-4971-444e-bb87-b6cd8cd2c9f6" alt=""><figcaption></figcaption></figure></div>

## Time and SpaceComplexity

|                                    | Time Complexity | Space Complexity                                                          |
| ---------------------------------- | --------------- | ------------------------------------------------------------------------- |
| Tabulation with Space Optimization | $$O(n^2)$$      | O(n)                                                                      |
| Tabulation                         | $$O(n^2)$$      | $$O(n^2)$$                                                                |
| Memoization                        | $$O(n^2)$$      | <p><span class="math">O(n^2) + O(h)</span></p><p>h -> recursion stack</p> |
| Recursion                          | $$O(2^n)$$      | $$O(n) + O(h)$$                                                           |

## Solution

```java
class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {

        // return recursionHelper(0, 0, triangle);
        // int n = triangle.size();
        // int[][] dp = new int[n][n];
        // for(int[] row: dp) {
        //     Arrays.fill(row, -1);
        // }

        // return memoizationHelper(0, 0, triangle, dp);

        // return tabulationHelper(triangle);
        return tabulationSpaceOptimisedHelper(triangle);
    }

    /**
     * Tabulation (Space Optimized) Approach:
     * Start from the bottom of the triangle and keep calculating the minimum path sum for each row.
     * Update the values in a rolling fashion, reusing the same space for storage.
     * Finally, the value at the top of the triangle represents the minimum path sum.
     *
     * Time Complexity: O(n^2), where n is the number of rows in the triangle.
     * Space Complexity: O(n), as we are using a single array to store intermediate values.
     */
    private int tabulationSpaceOptimisedHelper(List<List<Integer>> triangle) {
        int n = triangle.size();
        List<Integer> belowRow = triangle.get(n-1);

        for(int row = n-2;row >= 0;row--) {
            LinkedList<Integer> currentRow = new LinkedList<>();
            for(int col = row;col >= 0;col--) {
                int currentVal = triangle.get(row).get(col);
                int down = currentVal + belowRow.get(col);
                int diag = currentVal + belowRow.get(col+1);
                
                currentRow.addFirst(Math.min(down, diag));
            }
            belowRow = new ArrayList<>(currentRow);
        }

        return belowRow.get(0);
    }

    /**
     * Tabulation Approach:
     * Create a DP table to store the minimum path sum for each position in the triangle.
     * Start from the bottom row and fill the table by choosing the minimum path from the next row.
     * The minimum path sum at the top position represents the overall minimum path sum.
     *
     * Time Complexity: O(n^2), where n is the number of rows in the triangle.
     * Space Complexity: O(n^2), as we are using a 2D array to store intermediate values.
     */
    private int tabulationHelper(List<List<Integer>> triangle) {
        int n = triangle.size();
        int[][] dp = new int[n][n];

        for(int col=0;col<n;col++) {
            dp[n-1][col] = triangle.get(n-1).get(col);
        }

        for(int row=n-2;row>=0;row--) {
            for(int col=row;col>=0;col--) {
                int currentVal = triangle.get(row).get(col);
                int down = currentVal + dp[row+1][col];
                int diag = currentVal + dp[row+1][col+1];

                dp[row][col] = Math.min(down, diag);
            }
        }

        return dp[0][0];
    }

    /**
     * Memoization Approach:
     * Use a DP table to store the minimum path sum for each position in the triangle.
     * Recursively calculate the minimum path sum by choosing the minimum path from the next row.
     * Memoize the calculated values to avoid redundant computations.
     *
     * Time Complexity: O(n^2), where n is the number of rows in the triangle.
        It is actually less than that, but for sake of simplicity we call it O(n^2)
     * Space Complexity: O(n^2), as we are using a 2D array to store intermediate values.
     */
    private int memoizationHelper(int row, int col, List<List<Integer>> triangle, int[][] dp) {
        if(row == triangle.size()-1) {
            return triangle.get(row).get(col);
        }
        if(dp[row][col] != -1) {
            return dp[row][col];
        }

        int currentVal = triangle.get(row).get(col);
        int down = currentVal + recursionHelper(row+1, col, triangle);
        int diag = currentVal + recursionHelper(row+1, col+1, triangle);

        return dp[row][col] = Math.min(down, diag);
    }

    /**
     * Recursive Approach:
     * Recursively calculate the minimum path sum by choosing the minimum path from the next row.
     * Base case: If the current row is the last row, return the value at the current position.
     *
     * Time Complexity: O(2^n) Exponential, as there are overlapping subproblems.
     * Space Complexity: O(n), as the recursive calls occupy space on the call stack.
     */
    private int recursionHelper(int row, int col, List<List<Integer>> triangle) {
        if(row == triangle.size()-1) {
            return triangle.get(row).get(col);
        }

        int currentVal = triangle.get(row).get(col);
        int down = currentVal + recursionHelper(row+1, col, triangle);
        int diag = currentVal + recursionHelper(row+1, col+1, triangle);

        return Math.min(down, diag);
    }
}
```
