Open In App

Maximum Sum Increasing Subsequence

Last Updated : 10 Nov, 2025
Comments
Improve
Suggest changes
113 Likes
Like
Report

Given an array arr[] which consists of positive integers. Find the sum of the maximum sum subsequence of the given array such that the integers in the subsequence are sorted in strictly increasing order.

Examples:

Input: arr[] = [1, 101, 2, 3, 100]
Output: 106
Explanation: The maximum sum of a increasing sequence is obtained from [1, 2, 3, 100].

Input: arr[] = [4, 1, 2, 3]
Output: 6
Explanation: The maximum sum of a increasing sequence is obtained from [1, 2, 3].

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

This problem is a variation of the standard Longest Increasing Subsequence (LIS) problem. In this problem, we will consider the sum of subsequence instead of its length.

In this approach, we recursively explore all possible subsequences. For each index i, we decide whether to include it in the subsequence based on the last chosen index j. If a[i] > a[j], we have two choices — either include a[i] or skip it and we take the option that gives the maximum sum. If a[i] <= a[j], we cannot include a[i], so we simply move to the next index.

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


int findMaxSum(vector<int>& arr, int i, int j) {
    if(i == arr.size() + 1) return 0;
    
    // i - current index(1-based index)
    // j - last chosen index(1-based index)
    // if j = 0, no element is chosen
    if(j == 0 || arr[i-1] > arr[j-1]) {
        return max(arr[i-1] + findMaxSum(arr, i+1, i), 
                   findMaxSum(arr, i+1, j));
    }
    
    // if current element <= last chosen element
    // we can't chose current element
    else return findMaxSum(arr, i+1, j);
}

int maxSumIS(vector<int>& arr) {
    int n = arr.size();
    return findMaxSum(arr, 1, 0);
}

//Driver Code Starts

int main() {
    vector<int> arr = {1, 101, 2, 3, 100};
    cout << maxSumIS(arr);
}
//Driver Code Ends
Java
//Driver Code Starts
class GFG {
//Driver Code Ends

    static int findMaxSum(int[] arr, int i, int j) {
        if(i == arr.length + 1) return 0;
        
        // i - current index(1-based index)
        // j - last chosen index(1-based index)
        // if j = 0, no element is chosen
        if(j == 0 || arr[i-1] > arr[j-1]) {
            return Math.max(arr[i-1] + findMaxSum(arr, i+1, i), 
                                       findMaxSum(arr, i+1, j));
        }
        // if current element <= last chosen element
        // we can't chose current element
        else return findMaxSum(arr, i+1, j);
    }
    
    static int maxSumIS(int arr[]) {
        int n = arr.length;
        return findMaxSum(arr, 1, 0);
    }


//Driver Code Starts
    public static void main(String[] args) {
        int[] arr = {1, 101, 2, 3, 100};
        System.out.println(maxSumIS(arr));
    }
}

//Driver Code Ends
Python
def findMaxSum(arr, i, j):
    if i == len(arr) + 1:
        return 0
    
    # i - current index(1-based index)
    # j - last chosen index(1-based index)
    # if j = 0, no element is chosen
    if j == 0 or arr[i - 1] > arr[j - 1]:
        return max(arr[i - 1] + findMaxSum(arr, i + 1, i),
                   findMaxSum(arr, i + 1, j))
    # if current element <= last chosen element
    # we can't chose current element
    else:
        return findMaxSum(arr, i + 1, j)


def maxSumIS(arr):
    n = len(arr)
    return findMaxSum(arr, 1, 0)


#Driver Code Starts

if __name__ == "__main__":
    arr = [1, 101, 2, 3, 100]
    print(maxSumIS(arr))
#Driver Code Ends
C#
//Driver Code Starts
using System;

class GFG {
//Driver Code Ends

    static int findMaxSum(int[] arr, int i, int j) {
        if(i == arr.Length + 1) return 0;
        
        // i - current index(1-based index)
        // j - last chosen index(1-based index)
        // if j = 0, no element is chosen
        if(j == 0 || arr[i-1] > arr[j-1]) {
            return Math.Max(arr[i-1] + findMaxSum(arr, i+1, i), 
                            findMaxSum(arr, i+1, j));
        }
        // if current element <= last chosen element
        // we can't chose current element
        else return findMaxSum(arr, i+1, j);
    }
    
    static int maxSumIS(int[] arr) {
        int n = arr.Length;
        return findMaxSum(arr, 1, 0);
    }

//Driver Code Starts

    public static void Main() {
        int[] arr = {1, 101, 2, 3, 100};
        Console.WriteLine(maxSumIS(arr));
    }
}

//Driver Code Ends
JavaScript
function findMaxSum(arr, i, j) {
    if (i === arr.length + 1) return 0;
    
    // i - current index(1-based index)
    // j - last chosen index(1-based index)
    // if j = 0, no element is chosen
    if (j === 0 || arr[i - 1] > arr[j - 1]) {
        return Math.max(arr[i - 1] + findMaxSum(arr, i + 1, i),
                        findMaxSum(arr, i + 1, j)
        );
    }
    // if current element <= last chosen element
    // we can't chose current element
    else return findMaxSum(arr, i + 1, j);
}

function maxSumIS(arr) {
    let n = arr.length;
    return findMaxSum(arr, 1, 0);
}


//Driver Code Starts
// Driver code
let arr = [1, 101, 2, 3, 100];
console.log(maxSumIS(arr));

//Driver Code Ends

Output
106

[Better Approach 1] Using Top-Down DP (Memoization) - O(n2) Time and O(n2) Space

In the approach, we observe that many subproblems repeat. For example, while finding the maximum sum of an increasing subsequence starting at index i with the last chosen index j, we repeatedly compute results for the same (i, j) for several states (including or excluding i) across different recursive calls. To avoid recalculating these overlapping subproblems, we store the results of solved states in a DP table and reuse them whenever needed.

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


int findMaxSum(vector<int>& arr, int i, int j, vector<vector<int>>& dp) {
    if(i == arr.size() + 1) return 0;
    
    // if this subproblem is already solved
    // return the stored value
    if(dp[i][j] != -1) return dp[i][j];
    
    // i - current index(1-based index)
    // j - last chosen index(1-based index)
    // if j = 0, no element is chosen
    if(j == 0 || arr[i-1] > arr[j-1]) {
        return dp[i][j] = max(arr[i-1] + findMaxSum(arr, i+1, i, dp),
                              findMaxSum(arr, i+1, j, dp));
    }
    // if current element <= last chosen element
    // we can't chose current element
    else return dp[i][j] = findMaxSum(arr, i+1, j, dp);
}

int maxSumIS(vector<int>& arr) {
    int n = arr.size();
    vector<vector<int>> dp(n+1, vector<int>(n+1, -1));
    
    return findMaxSum(arr, 1, 0, dp);
}

//Driver Code Starts

int main() {
    vector<int> arr = {1, 101, 2, 3, 100};
    cout << maxSumIS(arr);
}
//Driver Code Ends
Java
//Driver Code Starts
import java.util.Arrays;

class GFG {
//Driver Code Ends

    static int findMaxSum(int[] arr, int i, int j, int[][] dp) {
        if(i == arr.length + 1) return 0;
        
        // if this subproblem is already solved
        // return the stored value
        if(dp[i][j] != -1 ) return dp[i][j];
        
        // i - current index(1-based index)
        // j - last chosen index(1-based index)
        // if j = 0, no element is chosen
        if(j == 0 || arr[i-1] > arr[j-1]) {
            return dp[i][j] = Math.max(arr[i-1] + findMaxSum(arr, i+1, i, dp), 
                                       findMaxSum(arr, i+1, j, dp));
        }
        // if current element <= last chosen element
        // we can't chose current element
        else return dp[i][j] = findMaxSum(arr, i+1, j, dp);
    }
    
    static int maxSumIS(int arr[]) {
        int n = arr.length;
        int[][] dp = new int[n+1][n+1];
        
        // initialize dp array with invalid value
        for( int[] row : dp ) {
            Arrays.fill(row, -1);
        }
        return findMaxSum(arr, 1, 0, dp);
    }

//Driver Code Starts

    public static void main(String[] args) {
        int[] arr = {1, 101, 2, 3, 100};
        
        System.out.println(maxSumIS(arr));
    }
}

//Driver Code Ends
Python
def findMaxSum(arr, i, j, dp):
    if i == len(arr) + 1:
        return 0

    # if this subproblem is already solved
    # return the stored value
    if dp[i][j] != -1:
        return dp[i][j]

    # i - current index(1-based index)
    # j - last chosen index(1-based index)
    # if j = 0, no element is chosen
    if j == 0 or arr[i - 1] > arr[j - 1]:
        dp[i][j] = max(
            arr[i - 1] + findMaxSum(arr, i + 1, i, dp),
            findMaxSum(arr, i + 1, j, dp)
        )
        return dp[i][j]
    # if current element <= last chosen element
    # we can't chose current element
    else:
        dp[i][j] = findMaxSum(arr, i + 1, j, dp)
        return dp[i][j]


def maxSumIS(arr):
    n = len(arr)
    dp = [[-1 for _ in range(n + 1)] for _ in range(n + 1)]

    # initialize dp array with invalid value
    for row in dp:
        for j in range(len(row)):
            row[j] = -1

    return findMaxSum(arr, 1, 0, dp)


#Driver Code Starts
if __name__ == "__main__":
    arr = [1, 101, 2, 3, 100]
    print(maxSumIS(arr))
#Driver Code Ends
C#
//Driver Code Starts
using System;

class GFG {
//Driver Code Ends

    static int findMaxSum(int[] arr, int i, int j, int[,] dp) {
        if(i == arr.Length + 1) return 0;
        
        // if this subproblem is already solved
        // return the stored value
        if(dp[i,j] != -1) return dp[i,j];
        
        // i - current index(1-based index)
        // j - last chosen index(1-based index)
        // if j = 0, no element is chosen
        if(j == 0 || arr[i-1] > arr[j-1]) {
            return dp[i,j] = Math.Max(arr[i-1] + findMaxSum(arr, i+1, i, dp), 
                                      findMaxSum(arr, i+1, j, dp));
        }
        // if current element <= last chosen element
        // we can't chose current element
        else return dp[i,j] = findMaxSum(arr, i+1, j, dp);
    }
    
    static int maxSumIS(int[] arr) {
        int n = arr.Length;
        int[,] dp = new int[n+1, n+1];
        
        // initialize dp array with invalid value
        for(int i = 0; i <= n; i++) {
            for(int j = 0; j <= n; j++) {
                dp[i,j] = -1;
            }
        }
        return findMaxSum(arr, 1, 0, dp);
    }

//Driver Code Starts

    public static void Main() {
        int[] arr = {1, 101, 2, 3, 100};
        Console.WriteLine(maxSumIS(arr));
    }
}
//Driver Code Ends
JavaScript
function findMaxSum(arr, i, j, dp) {
    if (i === arr.length + 1) return 0;
    
    // if this subproblem is already solved
    // return the stored value
    if (dp[i][j] !== -1) return dp[i][j];
    
    // i - current index(1-based index)
    // j - last chosen index(1-based index)
    // if j = 0, no element is chosen
    if (j === 0 || arr[i - 1] > arr[j - 1]) {
        return dp[i][j] = Math.max(
            arr[i - 1] + findMaxSum(arr, i + 1, i, dp),
            findMaxSum(arr, i + 1, j, dp)
        );
    }
    // if current element <= last chosen element
    // we can't chose current element
    else return dp[i][j] = findMaxSum(arr, i + 1, j, dp);
}

function maxSumIS(arr) {
    let n = arr.length;
    let dp = Array.from({ length: n + 1 }, () => Array(n + 1).fill(-1));
    
    // initialize dp array with invalid value
    for (let i = 0; i <= n; i++) {
        dp[i].fill(-1);
    }
    
    return findMaxSum(arr, 1, 0, dp);
}


//Driver Code Starts
// Driver code
let arr = [1, 101, 2, 3, 100];
console.log(maxSumIS(arr));
//Driver Code Ends

Output
106

[Better Approach 2] Using Bottom-Up DP (Tabulation) - O(n2) Time and O(n) Space

The main idea is to find the maximum sum increasing subsequence ending at each index i.
To do this, we look at all previous indices j such that arr[j] < arr[i]. This condition ensures that adding arr[i] at the end will keep the subsequence increasing. Among all such valid j, we find the one that gives the maximum sum subsequence ending at j, and then add arr[i] to extend it.
After calculating this for every index, we take the maximum value among all these subsequences — that’s our final answer.

C++
//Driver Code Starts
#include <bits/stdc++.h>
using namespace std;

//Driver Code Ends

int maxSumIS(vector<int>& arr) {
    int n = arr.size();
    vector<int> dp(n);
    dp[0] = arr[0];
    int ans = 0;
    for (int i = 0; i < n; i++) {
        // maximum sum of increasing 
        // subsequence ending at a value < a[i]
        int maxSum = 0;
        for (int j = 0; j < i; j++) {

            // taking max among all smaller indices
            if (arr[j] < arr[i]) maxSum = max(maxSum, dp[j]);
        }

        // adding current element to 
        // the subsequence with max sum
        dp[i] = maxSum + arr[i];
        ans = max(dp[i], ans);
    }
    return ans;
}

//Driver Code Starts

int main() {
    vector<int> arr = {1, 101, 2, 3, 100};
    cout << maxSumIS(arr);
}

//Driver Code Ends
Java
//Driver Code Starts
import java.util.Arrays;

class GFG {
//Driver Code Ends

    static int maxSumIS(int[] arr) {
        int n = arr.length;
        int[] dp = new int[n];
        dp[0] = arr[0];
        int ans = 0;
        for( int i = 0; i < n ; i++ ) {
            // maximum sum of increasing 
            // subsequence ending at a value < a[i]
            int maxSum = 0;
            for( int j = 0; j < i; j++ ) {
                
                // taking max among all smaller indices
                if( arr[j] < arr[i] ) maxSum = Math.max(maxSum, dp[j]);
            }
            
            // adding current element to 
            // the subsequence with max sum
            dp[i] = maxSum+arr[i];
            ans = Math.max(dp[i], ans);
        }
        return ans;
    }

//Driver Code Starts

    public static void main(String[] args) {
        int[] arr = {1, 101, 2, 3, 100};
        System.out.println(maxSumIS(arr));
    }
}

//Driver Code Ends
Python
def maxSumIS(arr):
    n = len(arr)
    dp = [0] * n
    dp[0] = arr[0]
    ans = 0
    for i in range(n):
        # maximum sum of increasing 
        # subsequence ending at a value < a[i]
        maxSum = 0
        for j in range(i):
            
            # taking max among all smaller indices
            if arr[j] < arr[i]:
                maxSum = max(maxSum, dp[j])
        
        # adding current element to 
        # the subsequence with max sum
        dp[i] = maxSum + arr[i]
        ans = max(dp[i], ans)
    return ans


#Driver Code Starts
if __name__ == "__main__":
    arr = [1, 101, 2, 3, 100]
    print(maxSumIS(arr))

#Driver Code Ends
C#
//Driver Code Starts
using System;

class GFG {
//Driver Code Ends

    static int MaxSumIS(int[] arr) {
        int n = arr.Length;
        int[] dp = new int[n];
        dp[0] = arr[0];
        int ans = 0;
        for (int i = 0; i < n; i++) {
            // maximum sum of increasing 
            // subsequence ending at a value < a[i]
            int maxSum = 0;
            for (int j = 0; j < i; j++) {

                // taking max among all smaller indices
                if (arr[j] < arr[i]) maxSum = Math.Max(maxSum, dp[j]);
            }

            // adding current element to 
            // the subsequence with max sum
            dp[i] = maxSum + arr[i];
            ans = Math.Max(dp[i], ans);
        }
        return ans;
    }

//Driver Code Starts

    public static void Main() {
        int[] arr = {1, 101, 2, 3, 100};
        Console.WriteLine(MaxSumIS(arr));
    }
}
//Driver Code Ends
JavaScript
function maxSumIS(arr) {
    const n = arr.length;
    const dp = new Array(n).fill(0);
    dp[0] = arr[0];
    let ans = 0;

    for (let i = 0; i < n; i++) {
        // maximum sum of increasing 
        // subsequence ending at a value < a[i]
        let maxSum = 0;
        for (let j = 0; j < i; j++) {

            // taking max among all smaller indices
            if (arr[j] < arr[i]) maxSum = Math.max(maxSum, dp[j]);
        }

        // adding current element to 
        // the subsequence with max sum
        dp[i] = maxSum + arr[i];
        ans = Math.max(dp[i], ans);
    }
    return ans;
}


//Driver Code Starts
// Driver code
const arr = [1, 101, 2, 3, 100];
console.log(maxSumIS(arr));

//Driver Code Ends

Output
106

[Expected Approach] Using Optimized Dynamic Programming - O(n log(n)) time and O(n) space

In the above approach, for every element, we look back through all previous elements to find the one with the highest subsequence sum among smaller values. We can observe that it can be optimized if we store-computed results in an ordered data structure that keeps elements sorted by their values. This allows us to quickly find the best result among all smaller elements using a logarithmic lookup, instead of checking each one individually.

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

//Driver Code Ends

int maxSumIS(vector<int>& arr) {
    
    // key = value in arr, value = max sum ending 
    // with that value or less than that value
    map<int, int> dp; 
    int ans = 0;

    for (int val : arr) {
        
        // Find the best sum among 
        // all elements smaller than val
        auto it = dp.lower_bound(val);
        int bestSmaller = 0;
        if (it != dp.begin()) {
            --it;
            bestSmaller = it->second;
        }

        int currSum = bestSmaller + val;

        // If this value gives a 
        // better sum, update TreeMap
        if (dp[val] < currSum) {
            dp[val] = currSum;

            // Remove entries with greater 
            // keys with smaller or equal sums
            auto higher = dp.upper_bound(val);
            while (higher != dp.end() && higher->second <= currSum) {
                higher = dp.erase(higher);
            }
        }

        ans = max(ans, currSum);
    }

    return ans;
}

//Driver Code Starts

int main() {
    vector<int> arr = {1, 101, 2, 3, 100};
    cout << maxSumIS(arr);
}
//Driver Code Ends
Java
//Driver Code Starts
import java.util.TreeMap;
import java.util.Map;

class GFG {
//Driver Code Ends

    static int maxSumIS(int[] arr) {
        
        // key = value in arr, value = max sum ending 
        // with that value or less than that value
        TreeMap<Integer, Integer> dp = new TreeMap<>(); 
        int ans = 0;

        for (int val : arr) {
            
            // Find the best sum among 
            // all elements smaller than val
            Map.Entry<Integer, Integer> entry = dp.lowerEntry(val);
            int bestSmaller = (entry == null) ? 0 : entry.getValue();

            int currSum = bestSmaller + val;

            // If this value gives a 
            // better sum, update TreeMap
            if (dp.getOrDefault(val, 0) < currSum) {
                dp.put(val, currSum);

                // Remove entries with greater 
                // keys with smaller or equal sums
                Integer higher = dp.higherKey(val);
                while (higher != null && dp.get(higher) <= currSum) {
                    dp.remove(higher);
                    higher = dp.higherKey(val);
                }
            }

            ans = Math.max(ans, currSum);
        }

        return ans;
    }

//Driver Code Starts

    public static void main(String[] args) {
        int[] arr = {1, 101, 2, 3, 100};
        System.out.println(maxSumIS(arr)); 
    }
}

//Driver Code Ends
Python
#Driver Code Starts
from bisect import bisect_left, insort

#Driver Code Ends

def maxSumIS(arr):
    
    # key = value in arr, value = max sum ending 
    # with that value or less than that value
    dp = {}
    keys = []
    ans = 0

    for val in arr:
        
        # Find the best sum among 
        # all elements smaller than val
        idx = bisect_left(keys, val)
        bestSmaller = 0
        if idx > 0:
            bestSmaller = dp[keys[idx - 1]]

        currSum = bestSmaller + val

        # If this value gives a 
        # better sum, update TreeMap
        if val not in dp or dp[val] < currSum:
            dp[val] = currSum
            if val not in keys:
                insort(keys, val)

            # Remove entries with greater 
            # keys with smaller or equal sums
            i = bisect_left(keys, val) + 1
            while i < len(keys):
                if dp[keys[i]] <= currSum:
                    del dp[keys[i]]
                    keys.pop(i)
                else:
                    break

        ans = max(ans, currSum)

    return ans

#Driver Code Starts

if __name__ == "__main__":
    arr = [1, 101, 2, 3, 100]
    print(maxSumIS(arr))

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

class GFG {
//Driver Code Ends

    static int MaxSumIS(int[] arr) {
        
        // key = value in arr, value = max sum ending 
        // with that value or less than that value
        SortedDictionary<int, int> dp = new SortedDictionary<int, int>(); 
        int ans = 0;

        foreach (int val in arr) {
            
            // Find the best sum among 
            // all elements smaller than val
            int bestSmaller = 0;
            foreach (var kv in dp) {
                if (kv.Key < val) bestSmaller = kv.Value;
                else break;
            }

            int currSum = bestSmaller + val;

            // If this value gives a 
            // better sum, update TreeMap
            if (!dp.ContainsKey(val) || dp[val] < currSum) {
                dp[val] = currSum;

                // Remove entries with greater 
                // keys with smaller or equal sums
                var keysToRemove = new List<int>();
                foreach (var kv in dp) {
                    if (kv.Key > val && kv.Value <= currSum)
                        keysToRemove.Add(kv.Key);
                }
                foreach (var k in keysToRemove)
                    dp.Remove(k);
            }

            ans = Math.Max(ans, currSum);
        }

        return ans;
    }

//Driver Code Starts

    public static void Main() {
        int[] arr = {1, 101, 2, 3, 100};
        Console.WriteLine(MaxSumIS(arr));
    }
}
//Driver Code Ends
JavaScript
function maxSumIS(arr) {
    
    // key = value in arr, value = max sum ending 
    // with that value or less than that value
    const dp = new Map(); 
    const sortedKeys = [];
    let ans = 0;

    for (const val of arr) {
        
        // Find the best sum among 
        // all elements smaller than val
        let bestSmaller = 0;
        for (const k of sortedKeys) {
            if (k < val) bestSmaller = Math.max(bestSmaller, dp.get(k));
            else break;
        }

        const currSum = bestSmaller + val;

        // If this value gives a 
        // better sum, update Map
        if (!dp.has(val) || dp.get(val) < currSum) {
            dp.set(val, currSum);
            if (!sortedKeys.includes(val)) {
                sortedKeys.push(val);
                sortedKeys.sort((a, b) => a - b);
            }

            // Remove entries with greater 
            // keys with smaller or equal sums
            for (let i = sortedKeys.length - 1; i >= 0; i--) {
                const higher = sortedKeys[i];
                if (higher > val && dp.get(higher) <= currSum) {
                    dp.delete(higher);
                    sortedKeys.splice(i, 1);
                }
            }
        }

        ans = Math.max(ans, currSum);
    }

    return ans;
}


//Driver Code Starts
// Driver code
const arr = [1, 101, 2, 3, 100];
console.log(maxSumIS(arr));

//Driver Code Ends

Output
106

Maximum Sum Increasing Subsequence

Explore