CMD Guide
HomeDSADynamic Programming

Maximum Sum Increasing Subsequence

Maximum Sum Increasing Subsequence

The maximum sum increasing subsequence (MSIS) is solved by extending each element with the best (highest-sum) increasing chain that can legally precede it — for every index i, look back at every earlier index j whose value is strictly smaller, take whichever gives the biggest running sum, and add nums[i] on top; the answer is the best running sum over all indices, not necessarily ending at the last element.

Recognize the pattern

Brute force → optimal

Brute force: enumerate every subsequence (2^n subsets), filter increasing ones, sum, take max. Time O(2^n · n), space O(n) for recursion — infeasible past n≈20.

Optimal (DP): define dp[i] = max sum of an increasing subsequence that ends at index i (element i included). For each i, scan all j < i; if nums[j] < nums[i], index i could extend that chain, so dp[i] = nums[i] + max(dp[j]) over qualifying j (or just nums[i] alone if no j qualifies). The final answer is max(dp[0..n-1]), because the best chain can end anywhere.

Plain patience sorting (the O(n log n) LIS trick) does not transfer as-is, because it tracks the smallest possible tail per length, and length is no longer the quantity being compared. But the O(n²) loop is not a hard floor: replace the inner scan with a coordinate-compressed Fenwick tree (or segment tree) keyed by value, storing the best dp seen so far at each value. For each i, a prefix-max query over "all compressed values less than nums[i]" replaces the inner loop, and a point update inserts dp[i] — both O(log n). That gives O(n log n) overall. Most interview settings still expect the simpler O(n²) DP first, with the Fenwick-tree version as a follow-up optimization.

Complexity, derived

Time: the outer loop runs n times; for each i the inner loop scans up to i prior elements. Total comparisons = 0+1+2+…+(n-1) = n(n-1)/2 → O(n²) for the straightforward DP. With coordinate compression plus a Fenwick/segment tree doing prefix-max queries and point updates, this drops to O(n log n).

Space: O(n) for the straightforward DP; O(n) for the Fenwick tree plus the compressed-value map for the faster version. (Reconstructing the actual subsequence, not just the sum, needs one more O(n) parent-pointer array in either version.)

Traced example

Input: {4, 1, 2, 6, 10, 1, 12}

inums[i]best prior dp[j] with nums[j]<nums[i]dp[i]
04none4
11none1
22dp[1]=13
36max(dp[0]=4, dp[1]=1, dp[2]=3) = 410
410max(4,1,3,10) = 10 (from dp[3])20
51none1
612max(4,1,3,10,20,1) = 20 (from dp[4])32

Answer = max(dp) = 32, reconstructed chain 4 → 6 → 10 → 12. Note the plain-LIS chain {1,2,6,10,12} sums to only 31 — MSIS correctly rejects it in favor of the higher-value chain.

Reference implementation

class Solution {
    public int findMaxSumIncreasingSubsequence(int[] nums) {
        int n = nums.length;
        if (n == 0) {
            // No elements: there is no subsequence, so define the sum as 0.
            // Callers that need "no answer exists" instead should special-case n == 0.
            return 0;
        }
        int[] dp = new int[n];
        int maxSum = Integer.MIN_VALUE;
        for (int i = 0; i < n; i++) {
            dp[i] = nums[i];
            for (int j = 0; j < i; j++) {
                if (nums[j] < nums[i]) {
                    dp[i] = Math.max(dp[i], dp[j] + nums[i]);
                }
            }
            maxSum = Math.max(maxSum, dp[i]);
        }
        return maxSum;
    }
}
func findMaxSumIncreasingSubsequence(nums []int) int {
    n := len(nums)
    if n == 0 {
        // No elements: there is no subsequence, so define the sum as 0.
        // Callers that need "no answer exists" instead should special-case n == 0.
        return 0
    }
    dp := make([]int, n)
    maxSum := math.MinInt32
    for i := 0; i < n; i++ {
        dp[i] = nums[i]
        for j := 0; j < i; j++ {
            if nums[j] < nums[i] && dp[j]+nums[i] > dp[i] {
                dp[i] = dp[j] + nums[i]
            }
        }
        if dp[i] > maxSum {
            maxSum = dp[i]
        }
    }
    return maxSum
}

Pitfalls

When to use / when not — trade-offs

Use the straightforward O(n²) DP whenever the metric to optimize (sum, product, count) is not simply "length," and n is modest (≤ ~5000 is typical in interview constraints) — it is simpler to write and to explain, and the constant factors are small. If the metric were plain length (standard LIS), prefer the patience-sorting / binary-search LIS algorithm — O(n log n) — since it only needs to track minimal tails per length, a trick that breaks once the objective is a sum (a shorter chain can beat a longer one in total value). For the sum objective at large n (10⁴–10⁵+), don't settle for O(n²): coordinate-compress the values and maintain a Fenwick/segment tree that answers "max dp among elements with strictly smaller value" — this gives the same O(n log n) asymptotics as LIS, at the cost of more code and a less obvious proof of correctness. Reach for the O(n²) version by default and reach for the tree-augmented version only when n is large enough that O(n²) actually times out.

Takeaways

Recall question: Why can't the O(n log n) patience-sorting technique used for plain LIS be adapted directly to maximize sum instead of length — and what data structure lets MSIS still reach O(n log n) by a different route?


Pattern: 1-D DP over sequences, dp[i] = best value ending at i, aggregated via a backward scan over valid predecessors (compare Longest Increasing Subsequence, Longest Bitonic Subsequence, Box Stacking).

🤖 Don't fully get this? Learn it with Claude

Stuck on Maximum Sum Increasing Subsequence? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **Maximum Sum Increasing Subsequence** (DSA) and want to truly understand it. Explain Maximum Sum Increasing Subsequence from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **Maximum Sum Increasing Subsequence** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **Maximum Sum Increasing Subsequence** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **Maximum Sum Increasing Subsequence** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes