Maximum Sum Increasing Subsequence
Last Updated :
10 Nov, 2025
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
[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
[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
[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
Maximum Sum Increasing Subsequence
Explore
DSA Fundamentals
Data Structures
Algorithms
Advanced
Interview Preparation
Practice Problem