Minimum Sum Path in a Triangle

Last Updated : 21 Jan, 2026

Given a triangular array triangle[], find the minimum path sum from top to bottom. We start from the first cell in the first row, and at each step, we can move to one of the two adjacent cells in the next row — that is, if we are at index i in the current row, we can move to either index i or i + 1 in the next row.

The triangular array contains 1 cell in 1st row, 2 cells in 2nd row and so on.

Examples : 

Input: triangle[][] = [[2],
[3, 7],
[8, 5, 6],
[6, 1, 9, 3]]
Output: 11
Explanation : The path is 2 -> 3 -> 5 -> 1, which results in a minimum sum of 2 + 3 + 5 + 1 = 11.

Input: triangle[][] = [[3],
[6, 9],
[8, 7, 1],
[9, 6, 8, 2]]
Output: 15
Explanation: The path is 3 -> 9 -> 1 -> 2, which results in a minimum sum of 3 + 9 + 1 + 2 = 15.

Try It Yourself
redirect icon

[Naive Approach] - Using Recursion – O(2 ^ (n*n)) Time and O(n) Space

At any position in the triangle, we can move only to one of the two adjacent positions in the next row.

So, to find the minimum path sum from a current cell (i, j), we need to consider both choices:

  1. Move to (i+1, j)
  2. Move to (i+1, j+1)

In order to find the answer for a cell in a row, we take the minimum among these two choices.

C++
//Driver Code Starts
#include <iostream>
#include <vector>
using namespace std;

//Driver Code Ends

int minSumPathRec(vector<vector<int>> &triangle, int i, int j) {

    // Base case: no value below the last row,
    // return 0
    if (i == triangle.size())
        return 0;

    // find the min path sum from 
    // current cell till the last row
    return triangle[i][j]
        + min(
            minSumPathRec(triangle, i + 1, j),
            minSumPathRec(triangle, i + 1, j + 1));
}

int minSumPath(vector<vector<int>> &triangle) {
    return minSumPathRec(triangle, 0, 0);
}

//Driver Code Starts

int main() {
    vector<vector<int>> triangle = {
        {2},
        {3, 9},
        {1, 6, 7}
    };

    cout << minSumPath(triangle);
}
//Driver Code Ends
Java
//Driver Code Starts
import java.util.ArrayList;
import java.util.List;

class GFG {
//Driver Code Ends

    static int minSumPathRec(ArrayList<ArrayList<Integer>> triangle,
                            int i, int j) {

        // Base case: no value below the last row,
        // return 0
        if (i == triangle.size())
            return 0;

        // find the min path sum from 
        // current cell till the last row
        return triangle.get(i).get(j)
            + Math.min(
                minSumPathRec(triangle, i+1, j),
                minSumPathRec(triangle, i+1, j+1));
    }

    static int minSumPath(ArrayList<ArrayList<Integer> > triangle) {
        return minSumPathRec(triangle, 0, 0);
    }

//Driver Code Starts

    public static void main(String[] args) {
        ArrayList<ArrayList<Integer> > triangle
            = new ArrayList<>();
        triangle.add(new ArrayList<>(List.of(2)));
        triangle.add(new ArrayList<>(List.of(3, 9)));
        triangle.add(new ArrayList<>(List.of(1, 6, 7)));

        System.out.println(minSumPath(triangle));
    }
}
//Driver Code Ends
Python
def minSumPathRec(triangle, i, j):

    #  Base case: no value below the last row,
    #  return 0
    if i == len(triangle):
        return 0

    # find the min path sum from 
    # current cell till the last row
    return triangle[i][j] + min(minSumPathRec(triangle, i+1, j),
                                minSumPathRec(triangle, i+1, j+1))


def minSumPath(triangle):
    return minSumPathRec(triangle, 0, 0)


#Driver Code Starts
if __name__ == "__main__":
    triangle = [
        [2],
        [3, 9],
        [1, 6, 7]
    ]
    
    print(minSumPath(triangle))

#Driver Code Ends
C#
//Driver Code Starts
using System;
using System.Collections.Generic;

class GFG {
//Driver Code Ends

    static int minSumPathRec(List<List<int>> triangle,
                             int i, int j) {

        // Base case: no value below the last row,
        // return 0
        if (i == triangle.Count)
            return 0;

        // find the min path sum from 
        // current cell till the last row
        return triangle[i][j]
               + Math.Min(
                minSumPathRec(triangle, i+1, j),
                minSumPathRec(triangle, i+1, j+1));
    }

    static int minSumPath(List<List<int> > triangle) {
        return minSumPathRec(triangle, 0, 0);
    }

//Driver Code Starts
    
    static void Main() {
      
        List<List<int> > triangle = new List<List<int>>{
            new List<int>{2}, 
            new List<int>{3, 9},
            new List<int>{1, 6, 7}
        };

        Console.WriteLine(minSumPath(triangle));
    }
}
//Driver Code Ends
JavaScript
function minSumPathRec(triangle, i, j) {

    // Base case: no value below the last row,
    // return 0
    if (i === triangle.length)
        return 0;

    // find the min path sum from 
    // current cell till the last row
    return triangle[i][j]
           + Math.min(
               minSumPathRec(triangle, i+1, j),
               minSumPathRec(triangle, i+1, j+1));
}

function minSumPath(triangle) {
    return minSumPathRec(triangle, 0, 0);
}


//Driver Code Starts
// Driver code
const triangle = [[2], [3, 9], [1, 6, 7]];
console.log(minSumPath(triangle));
//Driver Code Ends

Output
6

[Better Approach - 1] - Using Memoization – O(n*n) Time and O(n*n) Space

We observe that some of the subproblems overlap.

Like, in order to compute the answer for cell (i, j), we need answers for cells (i+1, j) and (i+1, j+1), and in order to compute the answer for cell (i, j+1), we need answers for cells (i+1, j+1) and (i+1, j+2). Here, the subproblems (i+1, j+1) is computed twice. Therefore, in order to avoid recomputing the same subproblems multiple times, we can store their results in a DP table and reuse them whenever needed.

C++
//Driver Code Starts
#include <iostream>
#include <vector>
using namespace std;

//Driver Code Ends

int minSumPathRec(vector<vector<int>> &triangle, int i,
                  int j, vector<vector<int>> &dp) {

    // Base Case
    if (i == triangle.size())
        return 0;

    // if the result for this subproblem is
    // already computed then return it
    if (dp[i][j] != -1)
        return dp[i][j];

    // Recurisve Case
    return dp[i][j] = triangle[i][j] +
    min(minSumPathRec(triangle, i+1, j, dp),
	minSumPathRec(triangle, i+1, j+1, dp));
}

int minSumPath(vector<vector<int>> &triangle) {
    int n = triangle.size();

    // dp array to store the result
    vector<vector<int>> dp(n, vector<int>(n, -1));
    return minSumPathRec(triangle, 0, 0, dp);
}

//Driver Code Starts

int main() {
    vector<vector<int>> triangle{{2}, {3, 9}, {1, 6, 7}};
    cout << minSumPath(triangle);
    return 0;
}
//Driver Code Ends
Java
//Driver Code Starts
import java.util.ArrayList;
import java.util.List;

class GFG {
//Driver Code Ends

    static int minSumPathRec(ArrayList<ArrayList<Integer>> triangle,
                            int i, int j, int[][] dp) {

        // Base Case
        if (i == triangle.size())
            return 0;

        // If the result for this subproblem is
        // already computed then return it
        if (dp[i][j] != -1)
            return dp[i][j];

        // Recursive Case
        return dp[i][j] = triangle.get(i).get(j)
              + Math.min(minSumPathRec(triangle, i+1, j, dp),
                  minSumPathRec(triangle, i+1, j+1, dp));
    }

    static int minSumPath(ArrayList<ArrayList<Integer>> triangle) {
        int n = triangle.size();

        // dp array to store the result
        int[][] dp = new int[n][n];
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                dp[i][j] = -1;

        return minSumPathRec(triangle, 0, 0, dp);
    }

//Driver Code Starts

    public static void main(String[] args) {
        ArrayList<ArrayList<Integer> > triangle
            = new ArrayList<>();
        triangle.add(new ArrayList<>(List.of(2)));
        triangle.add(new ArrayList<>(List.of(3, 9)));
        triangle.add(new ArrayList<>(List.of(1, 6, 7)));

        System.out.println(minSumPath(triangle));
    }
}
//Driver Code Ends
Python
def minSumPathRec(triangle, i, j, dp):

    # Base Case
    if i == len(triangle):
        return 0

    # if the result for this subproblem is
    # already computed then return it
    if dp[i][j] != -1:
        return dp[i][j]

    # Recursive Case
    dp[i][j] = triangle[i][j] + min(minSumPathRec(triangle, i+1, j, dp),
                                    minSumPathRec(triangle, i+1, j+1, dp))
    return dp[i][j]


def minSumPath(triangle):
    n = len(triangle)

    # dp array to store the result
    dp = [[-1] * n for i in range(n)]
    return minSumPathRec(triangle, 0, 0, dp)


#Driver Code Starts
triangle = [
    [2],
    [3, 9],
    [1, 6, 7]
]

print(minSumPath(triangle))

#Driver Code Ends
C#
//Driver Code Starts
using System;
using System.Collections.Generic;

class GFG {
//Driver Code Ends

    static int minSumPathRec(List<List<int>> triangle,
                             int i, int j, int[][] dp) {

        // Base Case
        if (i == triangle.Count)
            return 0;

        // If the result for this subproblem is
        // already computed then return it
        if (dp[i][j] != -1)
            return dp[i][j];

        // Recursive Case
        dp[i][j] = triangle[i][j] +
                   Math.Min(minSumPathRec(triangle, i+1, j, dp),
                   minSumPathRec(triangle, i+1, j+1, dp));
        return dp[i][j];
    }

    static int minSumPath(List<List<int> > triangle) {
        int n = triangle.Count;

        // dp array to store the result
        int[][] dp = new int[n][];
        for (int i = 0; i < n; i++) {
            dp[i] = new int[n];
            Array.Fill(dp[i], -1);
        }

        return minSumPathRec(triangle, 0, 0, dp);
    }

//Driver Code Starts

    static void Main() {
        List<List<int> > triangle = new List<List<int>>{
            new List<int>{2}, new List<int>{3, 9},
            new List<int>{1, 6, 7}
        };

        Console.WriteLine(minSumPath(triangle));
    }
}
//Driver Code Ends
JavaScript
function minSumPathRec(triangle, i, j, dp) {

    // Base Case
    if (i === triangle.length)
        return 0;

    // if the result for this subproblem is
    // already computed then return it
    if (dp[i][j] !== -1)
        return dp[i][j];

    // Recursive Case
    dp[i][j] = triangle[i][j] + 
               Math.min(minSumPathRec(triangle, i+1, j, dp),
               minSumPathRec(triangle, i+1, j+1, dp));
    return dp[i][j];
}

function minSumPath(triangle) {

    const n = triangle.length;

    // dp array to store the result
    const dp
        = Array.from({length : n}, () => Array(n).fill(-1));
    return minSumPathRec(triangle, 0, 0, dp);
}


//Driver Code Starts
const triangle = [[2], [3, 9], [1, 6, 7]];

console.log(minSumPath(triangle));
//Driver Code Ends

Output
6

[Better Approach - 2] - Using Tabulation – O(n*n) Time and O(n*n) Space

In this approach, we iteratively calculate the answers starting from the smallest subproblems — the last row of the triangle. The answer for any row depends on the answers of the rows below it. Using the precomputed results from the next row, we can efficiently compute the minimum path sums for the current row and store them for further use, continuing this process upward until we reach the top.

C++
//Driver Code Starts
#include <iostream>
#include <vector>
using namespace std;

//Driver Code Ends

int minSumPath(vector<vector<int>> &triangle) {
    int n = triangle.size();
  
  	// DP array to store the result
    vector<vector<int>> dp(n, vector<int>(n));
    
    // the last row will be same as triangle
    for (int i = 0; i < n; i++) 
        dp[n-1][i] = triangle[n - 1][i]; 

    // Calculation of the remaining rows,
    // in bottom up manner
    for (int i = n - 2; i >= 0; i--) 
        for (int j = 0; j < triangle[i].size(); j++) 
            dp[i][j] = triangle[i][j] + 
                       min(dp[i+1][j], dp[i+1][j+1]);

    return dp[0][0];
}

//Driver Code Starts

int main() {
    vector<vector<int> > triangle{{2},
                                  {3, 9},
                                  {1, 6, 7}};
    cout << minSumPath(triangle);
    return 0;
}
//Driver Code Ends
Java
//Driver Code Starts
import java.util.ArrayList;
import java.util.List;

class GFG {
//Driver Code Ends

    static int minSumPath(ArrayList<ArrayList<Integer>> triangle) {
        int n = triangle.size();
        
        // DP array to store the result
        int[][] dp = new int[n][n];
        
        // the last row will be same as triangle
        for( int j = 0; j < n; j++ ) 
            dp[n-1][j] = triangle.get(n-1).get(j);
            
        // Calculation of the remaining rows,
        // in bottom up manner
        for( int i = n-2 ; i >= 0 ; i-- ) {
            for( int j = 0; j <= i; j++ ) {
                dp[i][j] = triangle.get(i).get(j) +
                           Math.min(dp[i+1][j], dp[i+1][j+1]);
            }
        }
        return dp[0][0];
    }

//Driver Code Starts

    public static void main(String[] args) {
        ArrayList<ArrayList<Integer>> triangle
            = new ArrayList<>();
        triangle.add(new ArrayList<>(List.of(2)));
        triangle.add(new ArrayList<>(List.of(3, 9)));
        triangle.add(new ArrayList<>(List.of(1, 6, 7)));

        System.out.println(minSumPath(triangle));
    }
}
//Driver Code Ends
Python
def minSumPath(triangle):
    n = len(triangle)

    # DP array to store the result
    dp = [[0] * n for _ in range(n)]

    # The last row will be the same as triangle
    for i in range(n):
        dp[n - 1][i] = triangle[n - 1][i]

    # Calculation of the remaining rows,
    # in bottom up manner
    for i in range(n - 2, -1, -1):
        for j in range(len(triangle[i])):
            dp[i][j] = triangle[i][j] + \
                       min(dp[i+1][j], dp[i+1][j+1])

    return dp[0][0]


#Driver Code Starts

if __name__ == "__main__":
    triangle = [[2],
                [3, 9],
                [1, 6, 7]]

    print(minSumPath(triangle))

#Driver Code Ends
C#
//Driver Code Starts
using System;
using System.Collections.Generic;

class GFG {
//Driver Code Ends

    static int minSumPath(List<List<int>> triangle) {
        int n = triangle.Count;

        // DP array to store the result
        int[][] dp = new int[n][];
        for (int i = 0; i < n; i++) {
            dp[i] = new int[n];
        }

        // The last row will be the same as triangle
        for (int i = 0; i < n; i++)
            dp[n - 1][i] = triangle[n - 1][i];

        // Calculation of the remaining rows,
        // in bottom up manner
        for (int i = n - 2; i >= 0; i--)
            for (int j = 0; j < triangle[i].Count; j++)
                dp[i][j] = triangle[i][j]
                           + Math.Min(dp[i+1][j], dp[i+1][j+1]);

        return dp[0][0];
    }

//Driver Code Starts

    static void Main() {
        List<List<int> > triangle = new List<List<int>>{
            new List<int>{2}, 
            new List<int>{3, 9},
            new List<int>{1, 6, 7}
        };

        Console.WriteLine(minSumPath(triangle));
    }
}
//Driver Code Ends
JavaScript
function minSumPath(triangle) {
    const n = triangle.length;

    // DP array to store the result
    const dp = Array.from(Array(n), () => new Array(n));

    // The last row will be the same as triangle
    for (let i = 0; i < n; i++)
        dp[n - 1][i] = triangle[n - 1][i];

    // Calculation of the remaining rows,
    // in bottom up manner
    for (let i = n - 2; i >= 0; i--)
        for (let j = 0; j < triangle[i].length; j++)
            dp[i][j] = triangle[i][j]
                       + Math.min(dp[i+1][j], dp[i+1][j+1]);

    return dp[0][0];
}


//Driver Code Starts
//Driver code
const triangle = [[2], [3, 9], [1, 6, 7]];
console.log(minSumPath(triangle));
//Driver Code Ends

Output
6

[Expected Approach] - Using Space Optimized DP – O(n*n) Time and O(n) Space

In the above approach, we observe that in order to calculate the result for any cell in a row, we only need the answers of the next row in the triangle, specifically the two adjacent values directly below. Thus, while solving for a row, we use the answers of next row and store the answers for current one.

C++
//Driver Code Starts
#include <vector>
#include <iostream>
using namespace std;

//Driver Code Ends

int minSumPath(vector<vector<int>> &triangle) {
    int n = triangle.size();

    // 1-D dp to store the result
    vector<int> dp(n);

    // Base Case: Initially dp will be the
    // same as last row of matrix
    for (int i = 0; i < n; i++)
        dp[i] = triangle[n - 1][i];

    // Calculation of the remaining rows,
    // in bottom up manner
    for (int i = triangle.size() - 2; i >= 0; i--) {
        vector<int> new_dp(i + 1);
        for (int j = 0; j < triangle[i].size(); j++) {
            
            // calculating answers for current row
            new_dp[j] = triangle[i][j] + min(dp[j], dp[j + 1]);
        }
        dp = new_dp;
    }
    return dp[0];
}

//Driver Code Starts

int main() {
    vector<vector<int>> triangle = {
        {2},
        {3, 9},
        {1, 6, 7}
    };

    cout << minSumPath(triangle);
}

//Driver Code Ends
Java
//Driver Code Starts
import java.util.ArrayList;
import java.util.List;

class GFG {
//Driver Code Ends

    static int minSumPath(ArrayList<ArrayList<Integer>> triangle) {
        int n = triangle.size();

        // 1-D dp to store the result
        int[] dp = new int[n];

        // Base Case: Initially dp will be the
        // same as last row of matrix
        for (int i = 0; i < n; i++)
            dp[i] = triangle.get(n - 1).get(i);

        // Calculation of the remaining rows,
        // in bottom up manner
        for (int i = triangle.size() - 2; i >= 0; i--) {
            int[] new_dp = new int[i+1];
            for (int j = 0; j < triangle.get(i).size(); j++) {
                
                // calculating answers for current row
                new_dp[j] = triangle.get(i).get(j) + Math.min(dp[j], dp[j + 1]);
            }
            dp = new_dp;
        }
        return dp[0];
    }

//Driver Code Starts

    public static void main(String[] args) {
        ArrayList<ArrayList<Integer> > triangle
            = new ArrayList<>();
        triangle.add(new ArrayList<>(List.of(2)));
        triangle.add(new ArrayList<>(List.of(3, 9)));
        triangle.add(new ArrayList<>(List.of(1, 6, 7)));

        System.out.println(minSumPath(triangle));
    }
}
//Driver Code Ends
Python
def minSumPath(triangle):
    n = len(triangle)

    # 1-D dp to store the result
    dp = [0] * n

    # Base Case: Initially dp will be the
    # same as last row of matrix
    for i in range(n):
        dp[i] = triangle[n - 1][i]

    # Calculation of the remaining rows,
    # in bottom up manner
    for i in range(len(triangle) - 2, -1, -1):
        new_dp = [0] * (i + 1)
        for j in range(len(triangle[i])):
            
            # calculating answers for current row
            new_dp[j] = triangle[i][j] + min(dp[j], dp[j + 1])
        dp = new_dp
    return dp[0]


#Driver Code Starts
if __name__ == "__main__":
    triangle = [
        [2],
        [3, 9],
        [1, 6, 7]
    ]
    
    print(minSumPath(triangle))
#Driver Code Ends
C#
//Driver Code Starts
using System;
using System.Collections.Generic;

class GFG {
//Driver Code Ends

    static int minSumPath(List<List<int>> triangle) {
        int n = triangle.Count;

        // 1-D dp to store the result
        int[] dp = new int[n];

        // Base Case: Initially dp will be the
        // same as last row of matrix
        for (int i = 0; i < n; i++)
            dp[i] = triangle[n - 1][i];

        // Calculation of the remaining rows,
        // in bottom up manner
        for (int i = triangle.Count - 2; i >= 0; i--) {
            int[] new_dp = new int[i + 1];
            for (int j = 0; j < triangle[i].Count; j++) {
                
                // calculating answers for current row
                new_dp[j] = triangle[i][j] + Math.Min(dp[j], dp[j + 1]);
            }
            dp = new_dp;
        }
        return dp[0];
    }

//Driver Code Starts

    static void Main() {
        var triangle = new List<List<int>> {
            new List<int> {2},
            new List<int> {3, 9},
            new List<int> {1, 6, 7}
        };

        Console.WriteLine(minSumPath(triangle));
    }
}
//Driver Code Ends
JavaScript
function minSumPath(triangle) {
    const n = triangle.length;

    // 1-D dp to store the result
    let dp = new Array(n);

    // Base Case: Initially dp will be the
    // same as last row of matrix
    for (let i = 0; i < n; i++)
        dp[i] = triangle[n - 1][i];

    // Calculation of the remaining rows,
    // in bottom up manner
    for (let i = triangle.length - 2; i >= 0; i--) {
        let new_dp = new Array(i + 1);
        for (let j = 0; j < triangle[i].length; j++) {
            
            // calculating answers for current row
            new_dp[j] = triangle[i][j] + Math.min(dp[j], dp[j + 1]);
        }
        dp = new_dp;
    }
    return dp[0];
}


//Driver Code Starts
// Driver code
const triangle = [
    [2],
    [3, 9],
    [1, 6, 7]
];

console.log(minSumPath(triangle));
//Driver Code Ends

Output
6
Comment