Triangle

MediumDynamic Programming · Grid DP🧩 Grid DPLeetCode #120 ↗Updated

Problem

You are given a number triangle as a list of rows, where row r holds r + 1 integers. Start at the single top value and walk to the bottom row; from index c you may step to index c or c + 1 of the next row. Return the smallest possible sum of the values along such a walk.
Input[[2],[3,4],[6,5,7],[4,1,8,3]]Output11 (2 + 3 + 5 + 1)
Input[[-10]]Output-10

1 ≤ rows ≤ 200  ·  -104 ≤ value ≤ 104  ·  Follow-up: use only O(rows) extra space.

Try it yourself

Java
class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        
    }
}
Your code is saved in this browser.Submit on LeetCode ↗
Key insight
Work bottom-up: the best walk starting at (r, c) is its value plus the cheaper of the two best walks just below it. The bottom row is its own answer, and the top cell ends up holding the result — one array of length rows suffices.
PatternGrid DP

Instinct Grid moves that never loop back (right/down, row to row) plus "count or optimise the paths" - build dp[r][c] from the cells that can step in.

Memory hack Every cell asks its parents - a cell's answer comes only from the neighbours that can move into it, so fill cells in the order they arrive.

Open the Grid DP guide →

Approaches

Brute ForceTry Every Walk (Recursion)

Time O(2n)Space O(n)

From each cell, recursively compute the best walk through the left child and the right child and keep the smaller. Every one of the 2n-1 walks is explored.

Java
public int minimumTotal(List<List<Integer>> triangle) {
    return best(triangle, 0, 0);
}

// Minimum sum of a walk that starts at (r, c) and ends on the last row
private int best(List<List<Integer>> tri, int r, int c) {
    int value = tri.get(r).get(c);
    if (r == tri.size() - 1) return value;
    return value + Math.min(best(tri, r + 1, c), best(tri, r + 1, c + 1));
}

Direct translation of the rules, but inner cells are re-solved many times.

At a glance

LevelApproachTimeSpace
Brute ForceTry Every Walk (Recursion)O(2n)O(n)
BetterTop-Down MemoizationO(n2)O(n2)
OptimalBottom-Up 1-D DPO(n2)O(n)
Common pitfalls
  • Greedy “take the smaller child” — a cheap step can lead into an expensive subtree.
  • Using int[][] memo with 0 as “unset” — 0 (or negatives) are real sums.
  • Top-down in place needs a final min over the last row; bottom-up does not.
Interview tips
  • Ask whether you may modify the input — if yes, you can even reuse the last row.
  • Explain why left-to-right is safe in the 1-D update (dp[c+1] is read before overwritten).
  • Show a counter-example to greedy before jumping into DP.
Pattern
Path DP on a DAG-shaped grid → each cell's best depends on a few neighbours in the next row, so roll one row of state.
My notes saved in this browser