Non-decreasing subsequence of size k with minimum sum

Last Updated : 4 Jun, 2026

Given a sequence of n integers, find out the non-decreasing subsequence of length k with minimum sum. If no sequence exists output -1.

Examples : 

Input: k = 3, arr[] = [58, 12, 11, 12, 82, 30, 20, 77, 16, 86]
Output: 39
Explanation: Non-decreasing subsequence of length 3 with minimum sum is: [11, 12, 16].

Input: k = 4, arr[] = [58, 12, 11, 12, 82, 30, 20, 77, 16, 86]
Output: 120
Explanation: Non-decreasing subsequence of length 4 with minimum sum is: [11, 12, 20, 77].

Try It Yourself
redirect icon

[Naive Approach] Using Simple Dynamic Programming - O(k * n2) Time O(n) Space

This can be seen as a variation of Longest Increasing Subsequence. For each index, we try all previous indices to build a non-decreasing subsequence. We maintain a DP array where dp[i] stores the minimum sum of a subsequence of current length ending at index i. For every length from 2 to k, we check all j < i and if arr[j] <= arr[i], we update the minimum sum. Finally, the minimum value among all valid subsequences of length k is returned, or -1 if no such subsequence exists.

C++
#include <iostream>
using namespace std;

// function to find Min Sum Non-decreasing Subsequence of Size k
int minSum(int k, vector<int> &arr)
{
    int n = arr.size();

    if (k > n)
        return -1;

    const int INF = 1e9;

    // dp[i] = min sum of subsequence of current length ending at i
    vector<int> dp(n);

    // Base case: length = 1
    for (int i = 0; i < n; i++)
        dp[i] = arr[i];

    // Build for lengths 2 to k
    for (int len = 2; len <= k; len++)
    {
        vector<int> next_dp(n, INF);

        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < i; j++)
            {
                // check non-decreasing condition
                if (arr[j] <= arr[i] && dp[j] != INF)
                {
                    next_dp[i] = min(next_dp[i], dp[j] + arr[i]);
                }
            }
        }

        dp = next_dp;
    }

    // get answer
    int ans = INF;
    for (int i = 0; i < n; i++)
        ans = min(ans, dp[i]);

    return ans == INF ? -1 : ans;
}

// Driver Code
int main() {
    int k = 3;
    vector<int> arr = {58, 12, 11, 12, 82, 30, 20, 77, 16, 86};

    cout << minSum(k, arr);

    return 0;
}
Java
import java.util.Arrays;

public class GfG {
    // function to find Min Sum Non-decreasing Subsequence of Size k
    public static int minSum(int k, int[] arr) {
        int n = arr.length;

        if (k > n)
            return -1;

        final int INF = (int) 1e9;

        // dp[i] = min sum of subsequence of current length ending at i
        int[] dp = new int[n];
        Arrays.fill(dp, INF);

        // Base case: length = 1
        for (int i = 0; i < n; i++)
            dp[i] = arr[i];

        // Build for lengths 2 to k
        for (int len = 2; len <= k; len++) {
            int[] next_dp = new int[n];
            Arrays.fill(next_dp, INF);

            for (int i = 0; i < n; i++) {
                for (int j = 0; j < i; j++) {
                    // check non-decreasing condition
                    if (arr[j] <= arr[i] && dp[j]!= INF) {
                        next_dp[i] = Math.min(next_dp[i], dp[j] + arr[i]);
                    }
                }
            }

            dp = next_dp;
        }

        // get answer
        int ans = INF;
        for (int i = 0; i < n; i++)
            ans = Math.min(ans, dp[i]);

        return ans == INF? -1 : ans;
    }

    // Driver Code
    public static void main(String[] args) {
        int k = 3;
        int[] arr = {58, 12, 11, 12, 82, 30, 20, 77, 16, 86};

        System.out.println(minSum(k, arr));
    }
}
Python
from typing import List

# function to find Min Sum Non-decreasing Subsequence of Size k


def minSum(k: int, arr: List[int]) -> int:
    n = len(arr)

    if k > n:
        return -1

    INF = int(1e9)

    # dp[i] = min sum of subsequence of current length ending at i
    dp = [arr[i] for i in range(n)]

    # Build for lengths 2 to k
    for length in range(2, k + 1):  # FIXED
        next_dp = [INF] * n

        for i in range(n):
            for j in range(i):
                # check non-decreasing condition
                if arr[j] <= arr[i] and dp[j] != INF:
                    next_dp[i] = min(next_dp[i], dp[j] + arr[i])

        dp = next_dp

    # get answer
    ans = INF
    for i in range(n):
        ans = min(ans, dp[i])

    return -1 if ans == INF else ans


# Driver Code
if __name__ == "__main__":
    k = 3
    arr = [58, 12, 11, 12, 82, 30, 20, 77, 16, 86]
    print(minSum(k, arr))
C#
using System;
using System.Collections.Generic;

class GfG
{
    // function to find Min Sum Non-decreasing Subsequence of Size k
    static int minSum(int k, int[] arr)
    {
        int n = arr.Length;

        if (k > n)
            return -1;

        const int INF = 1000000000;

        // dp[i] = min sum of subsequence of current length ending at i
        int[] dp = new int[n];

        // Base case: length = 1
        for (int i = 0; i < n; i++)
            dp[i] = arr[i];

        // Build for lengths 2 to k
        for (int len = 2; len <= k; len++)
        {
            int[] next_dp = new int[n];
            Array.Fill(next_dp, INF);

            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < i; j++)
                {
                    // check non-decreasing condition
                    if (arr[j] <= arr[i] && dp[j]!= INF)
                    {
                        next_dp[i] = Math.Min(next_dp[i], dp[j] + arr[i]);
                    }
                }
            }

            dp = next_dp;
        }

        // get answer
        int ans = INF;
        for (int i = 0; i < n; i++)
            ans = Math.Min(ans, dp[i]);

        return ans == INF ? -1 : ans;
    }

    // Driver Code
    static void Main()
    {
        int k = 3;
        int[] arr = {58, 12, 11, 12, 82, 30, 20, 77, 16, 86};

        Console.WriteLine(minSum(k, arr));
    }
}
JavaScript
function minSum(k, arr) {
    const n = arr.length;

    if (k > n)
        return -1;

    const INF = 1e9;

    // dp[i] = min sum of subsequence of current length ending at i
    let dp = Array(n).fill(0);

    // Base case: length = 1
    for (let i = 0; i < n; i++)
        dp[i] = arr[i];

    // Build for lengths 2 to k
    for (let len = 2; len <= k; len++) {
        let next_dp = Array(n).fill(INF);

        for (let i = 0; i < n; i++) {
            for (let j = 0; j < i; j++) {
                // check non-decreasing condition
                if (arr[j] <= arr[i] && dp[j]!== INF) {
                    next_dp[i] = Math.min(next_dp[i], dp[j] + arr[i]);
                }
            }
        }

        dp = next_dp;
    }

    // get answer
    let ans = INF;
    for (let i = 0; i < n; i++) {
        ans = Math.min(ans, dp[i]);
    }

    return ans === INF? -1 : ans;
}

// Driver Code
const k = 3;
const arr = [58, 12, 11, 12, 82, 30, 20, 77, 16, 86];

console.log(minSum(k, arr));

Output
39

Time Complexity: O(k * n²)
Space Complexity: O(n)

[Expected Approach] Using Dynamic Programming with Fenwick Tree - O(k * n * log n) Time O(n + m) Space 

The idea is to use Dynamic Programming to efficiently find the minimum sum non-decreasing subsequence of size k. We store the minimum sum ending at each index and, for every length, use a Fenwick Tree to quickly get the best previous valid sum (where elements are ≤ current element). This helps maintain the non-decreasing property while minimizing the sum. Finally, we return the minimum value obtained for length k, or -1 if not possible.

Working of Approach:

  • Compress the array values into ranks and use Coordinate Compression so that they can be efficiently processed using a Fenwick Tree (BIT).
  • Let dp[i] denote the minimum sum of a non-decreasing subsequence of the current length ending at index i. For length 1, initialize dp[i] = arr[i].
  • For every subsequence length from 2 to k, use the Fenwick Tree to find the minimum DP value among all previous elements having value less than or equal to arr[i].
  • If such a subsequence exists, extend it by including arr[i] and store the new minimum sum in next_dp[i]. Update the Fenwick Tree with the current DP values for future transitions.
  • After processing all lengths up to k, the minimum value in the final DP array gives the minimum sum of a non-decreasing subsequence of size k. If no valid subsequence exists, return -1.
C++
#include <bits/stdc++.h>
using namespace std;

// function to find Min Sum Non-decreasing Subsequence of Size k
int minSum(int k, vector<int> &arr)
{
    int n = arr.size();

    // Edge case: if we need a sequence longer than the array itself
    if (k > n)
        return -1;

    if (k == 1)
    {
        int mn = arr[0];
        for (int x : arr)
            mn = min(mn, x);
        return mn;
    }

    // 1.Coordinate Compression
    vector<int> sorted_arr = arr;
    sort(sorted_arr.begin(), sorted_arr.end());
    sorted_arr.erase(unique(sorted_arr.begin(), sorted_arr.end()), sorted_arr.end());
    int max_val = sorted_arr.size();

    // Map original array values to their 1-based ranks
    vector<int> rank(n);
    for (int i = 0; i < n; i++)
    {
        rank[i] = lower_bound(sorted_arr.begin(), sorted_arr.end(), arr[i]) - sorted_arr.begin() + 1;
    }

    const int INF = 1e9; // Large enough to act as infinity
    vector<int> dp(n);

    // Base case: subsequences of length 1
    for (int i = 0; i < n; i++)
    {
        dp[i] = arr[i];
    }

    // 2. Compute DP for lengths 2 to k
    for (int len = 2; len <= k; len++)
    {
        vector<int> next_dp(n, INF);
        vector<int> bit(max_val + 1, INF);

        // Helper to update the BIT with the minimum value
        auto update = [&](int idx, int val) {
            for (; idx <= max_val; idx += idx & -idx)
            {
                bit[idx] = min(bit[idx], val);
            }
        };

        // Helper to query the minimum value up to a specific rank
        auto query = [&](int idx) {
            int res = INF;
            for (; idx > 0; idx -= idx & -idx)
            {
                res = min(res, bit[idx]);
            }
            return res;
        };

        for (int i = 0; i < n; i++)
        {
            // Query the minimum sum from the previous length where the ending value
            // is <= arr[i]
            int min_prev = query(rank[i]);

            if (min_prev != INF)
            {
                next_dp[i] = arr[i] + min_prev;
            }

            // Update the BIT with the previously computed length's value at the
            // current rank
            if (dp[i] != INF)
            {
                update(rank[i], dp[i]);
            }
        }
        dp = next_dp; // Move to the next length
    }

    // 3. Find the global minimum for length k
    int ans = INF;
    for (int i = 0; i < n; i++)
    {
        ans = min(ans, dp[i]);
    }

    return ans == INF ? -1 : ans;
}

// Driver Code
int main() {
    int k = 3;
    vector<int> arr = {58, 12, 11, 12, 82, 30, 20, 77, 16, 86};

    cout << minSum(k, arr);

    return 0;
}
Java
import java.util.*;

// function to find Min Sum Non-decreasing Subsequence of Size k
public class GfG {
    public static int minSum(int k, int[] arr)
    {
        int n = arr.length;

        // Edge case: if we need a sequence longer than the array itself
        if (k > n)
            return -1;

        if (k == 1) {
            int mn = arr[0];
            for (int x : arr)
                mn = Math.min(mn, x);
            return mn;
        }

        // 1. Coordinate Compression
        int[] sortedArr = arr.clone();
        Arrays.sort(sortedArr);

        // Remove duplicates to get unique values
        int uniqueCount = 0;
        for (int i = 0; i < n; i++) {
            if (i == 0 || sortedArr[i] != sortedArr[i - 1]) {
                sortedArr[uniqueCount++] = sortedArr[i];
            }
        }

        // Map original array values to their 1-based ranks
        int[] rank = new int[n];
        for (int i = 0; i < n; i++) {
            rank[i] = Arrays.binarySearch(
                          sortedArr, 0, uniqueCount, arr[i]) + 1;
        }

        int INF = (int)1e9;
        int[] dp = new int[n];

        // Base case: subsequences of length 1
        for (int i = 0; i < n; i++) {
            dp[i] = arr[i];
        }

        // 2. Compute DP for lengths 2 to k
        for (int len = 2; len <= k; len++) {
            int[] next_dp = new int[n];
            Arrays.fill(next_dp, INF);
            int[] bit = new int[uniqueCount + 1];
            Arrays.fill(bit, INF);

            for (int i = 0; i < n; i++) {
                int min_prev = INF;

                for (int idx = rank[i]; idx > 0; idx -= idx & -idx) {
                    min_prev = Math.min(min_prev, bit[idx]);
                }

                if (min_prev != INF) {
                    next_dp[i] = arr[i] + min_prev;
                }

                if (dp[i] != INF) {
                    for (int idx = rank[i]; idx <= uniqueCount; idx += idx & -idx) {
                        bit[idx] = Math.min(bit[idx], dp[i]);
                    }
                }
            }
            dp = next_dp;
        }

        // 3. Find the global minimum for length k
        int ans = INF;
        for (int i = 0; i < n; i++) {
            ans = Math.min(ans, dp[i]);
        }

        return ans == INF ? -1 : ans;
    }

    // Driver Code
    public static void main(String[] args)
    {
        int k = 3;
        int[] arr = {58, 12, 11, 12, 82, 30, 20, 77, 16, 86};

        System.out.println(minSum(k, arr));
    }
}
Python
from bisect import bisect_left
from typing import List

# function to find Min Sum Non-decreasing Subsequence of Size k
def minSum(k, arr):
    n = len(arr)

    # Edge case: if we need a sequence longer than the array itself
    if k > n:
        return -1

    if k == 1:
        return min(arr)

    # 1. Coordinate Compression
    sorted_unique = sorted(list(set(arr)))
    max_val = len(sorted_unique)
    rank_map = {val: i + 1 for i, val in enumerate(sorted_unique)}

    # Map original array values to their 1-based ranks
    rank = [rank_map[x] for x in arr]

    INF = int(1e9)  # Large enough to act as infinity
    dp = arr[:]  # Base case: subsequences of length 1

    # 2. Compute DP for lengths 2 to k
    for length in range(2, k + 1):
        next_dp = [INF] * n
        bit = [INF] * (max_val + 1)

        # Helper to update the BIT
        def update(idx, val):
            while idx <= max_val:
                if val < bit[idx]:
                    bit[idx] = val
                idx += idx & -idx

        # Helper to query the BIT
        def query(idx):
            res = INF
            while idx > 0:
                if bit[idx] < res:
                    res = bit[idx]
                idx -= idx & -idx
            return res

        for i in range(n):
            min_prev = query(rank[i])

            if min_prev != INF:
                next_dp[i] = arr[i] + min_prev

            if dp[i] != INF:
                update(rank[i], dp[i])

        dp = next_dp  # Move to the next length

    # 3. Find the global minimum for length k
    ans = min(dp)
    return -1 if ans == INF else ans


# Driver Code
if __name__ == "__main__":
    k = 3
    arr = [58, 12, 11, 12, 82, 30, 20, 77, 16, 86]
    print(minSum(k, arr))
C#
using System;

public class GfG {
    // function to find Min Sum Non-decreasing Subsequence
    // of Size k
    public int minSum(int k, int[] arr)
    {
        int n = arr.Length;

        if (k > n)
            return -1;

        if (k == 1) {
            int mn = arr[0];
            foreach(int x in arr) mn = Math.Min(mn, x);
            return mn;
        }

        int[] sortedArr = (int[])arr.Clone();
        Array.Sort(sortedArr);

        int uniqueCount = 0;
        for (int i = 0; i < n; i++) {
            if (i == 0 || sortedArr[i] != sortedArr[i - 1]) {
                sortedArr[uniqueCount++] = sortedArr[i];
            }
        }

        int[] rank = new int[n];
        for (int i = 0; i < n; i++) {
            rank[i] = Array.BinarySearch(sortedArr, 0, uniqueCount, arr[i]) + 1;
        }

        int INF = (int)1e9;
        int[] dp = new int[n];

        for (int i = 0; i < n; i++) {
            dp[i] = arr[i];
        }

        for (int len = 2; len <= k; len++) {
            int[] next_dp = new int[n];
            Array.Fill(next_dp, INF);
            int[] bit = new int[uniqueCount + 1];
            Array.Fill(bit, INF);

            for (int i = 0; i < n; i++) {
                int min_prev = INF;
                for (int idx = rank[i]; idx > 0; idx -= idx & -idx) {
                    min_prev = Math.Min(min_prev, bit[idx]);
                }

                if (min_prev != INF) {
                    next_dp[i] = arr[i] + min_prev;
                }

                if (dp[i] != INF) {
                    for (int idx = rank[i]; idx <= uniqueCount; idx += idx & -idx) {
                        bit[idx] = Math.Min(bit[idx], dp[i]);
                    }
                }
            }
            dp = next_dp;
        }

        int ans = INF;
        for (int i = 0; i < n; i++) {
            ans = Math.Min(ans, dp[i]);
        }

        return ans == INF ? -1 : ans;
    }

    // Driver Code
    public static void Main()
    {
        int k = 3;
        int[] arr = { 58, 12, 11, 12, 82, 30, 20, 77, 16, 86 };

        GfG obj = new GfG(); 
        Console.WriteLine(obj.minSum(k, arr)); 
    }
}
JavaScript
// function to find Min Sum Non-decreasing Subsequence of
// Size k
function minSum(k, arr)
{
    let n = arr.length;

    // Edge case: if we need a sequence longer than the
    // array itself
    if (k > n)
        return -1;

    if (k === 1) {
        let mn = arr[0];
        for (let x of arr)
            mn = Math.min(mn, x);
        return mn;
    }

    // 1. Coordinate Compression
    let sorted_arr = arr.slice().sort((a, b) => a - b);
    sorted_arr = [...new Set(sorted_arr) ];
    let max_val = sorted_arr.length;

    // Map original array values to their 1-based ranks
    let rank = new Array(n);
    for (let i = 0; i < n; i++) {
        rank[i] = sorted_arr.indexOf(arr[i]) + 1;
    }

    const INF = 1e9; // Large enough to act as infinity
    let dp = new Array(n);

    // Base case: subsequences of length 1
    for (let i = 0; i < n; i++) {
        dp[i] = arr[i];
    }

    // 2. Compute DP for lengths 2 to k
    for (let len = 2; len <= k; len++) {
        let next_dp = new Array(n).fill(INF);
        let bit = new Array(max_val + 1).fill(INF);

        // Helper to update the BIT with the minimum value
        const update = (idx, val) => {
            for (; idx <= max_val; idx += idx & -idx) {
                bit[idx] = Math.min(bit[idx], val);
            }
        };

        // Helper to query the minimum value up to a
        // specific rank
        const query = (idx) => {
            let res = INF;
            for (; idx > 0; idx -= idx & -idx) {
                res = Math.min(res, bit[idx]);
            }
            return res;
        };

        for (let i = 0; i < n; i++) {
            // Query the minimum sum from the previous
            // length where the ending value is <= arr[i]
            let min_prev = query(rank[i]);

            if (min_prev !== INF) {
                next_dp[i] = arr[i] + min_prev;
            }

            // Update the BIT with the previously computed
            // length's value at the current rank
            if (dp[i] !== INF) {
                update(rank[i], dp[i]);
            }
        }
        dp = next_dp; // Move to the next length
    }

    // 3. Find the global minimum for length k
    let ans = INF;
    for (let i = 0; i < n; i++) {
        ans = Math.min(ans, dp[i]);
    }

    return ans === INF ? -1 : ans;
}

// Driver Code
const k = 3;
const arr = [ 58, 12, 11, 12, 82, 30, 20, 77, 16, 86 ];

console.log(minSum(k, arr));

Output
39

Time Complexity: O(k * n * log n)
Space Complexity: O(n + m)

Comment