Maximum product of an increasing subsequence of size 3

Last Updated : 18 Jun, 2026

Given an array arr[] of non-negative integers, find the subsequence of length 3 with the maximum product such that the elements of the subsequence are in strictly increasing order. Return the 3 elements as a list. If no such subsequence exists, return an empty list.

Examples:

Input: arr[] = [6, 7, 8, 1, 2, 3, 9, 10]
Output: 8 9 10
Explanation: 3 increasing elements of the given arrays are 8,9 and 10 which forms the subsequence of size 3 with maximum product.

Input: arr[] = [3, 4, 2, 1]
Output: []
Explanation: No strictly increasing subsequence of length 3 exists, so an empty list is returned.

Try It Yourself
redirect icon

[Naive Approach] Using Brute Force - O(n^3) Time and O(1) Space

Try all possible triplets (i, j, k) where i < j < k. For each triplet check if elements are in strictly increasing order. If yes compute the product and update the maximum. Return the triplet with maximum product.

  • For every triplet i < j < k check if arr[i] < arr[j] < arr[k].
  • Compute product arr[i] * arr[j] * arr[k] and update result if greater than current maximum.
  • If no valid triplet found return empty list.
C++
#include <bits/stdc++.h>
using namespace std;

vector<int> maxProductSubsequence(vector<int>& arr) {
    int n = arr.size();
    long long maxProd = -1;
    vector<int> res;

    // Try all triplets i < j < k with arr[i] < arr[j] < arr[k]
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            for (int k = j + 1; k < n; k++) {
                if (arr[i] < arr[j] && arr[j] < arr[k]) {
                    long long prod = (1LL * arr[i]) * arr[j] * arr[k];
                    if (prod > maxProd) {
                        maxProd = prod;
                        res = {arr[i], arr[j], arr[k]};
                    }
                }
            }
        }
    }
    return res;
}

int main() {
    vector<int> arr = {6, 7, 8, 1, 2, 3, 9, 10};
    vector<int> res = maxProductSubsequence(arr);
    for (int x : res) cout << x << " ";
    return 0;
}
Java
import java.util.*;

class GfG {

    static List<Integer> maxProductSubsequence(int[] arr) {
        int n = arr.length;
        long maxProd = -1;
        List<Integer> res = new ArrayList<>();

        // Try all triplets i < j < k with arr[i] < arr[j] < arr[k]
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                for (int k = j + 1; k < n; k++) {
                    if (arr[i] < arr[j] && arr[j] < arr[k]) {
                        long prod = (long) arr[i] * arr[j] * arr[k];
                        if (prod > maxProd) {
                            maxProd = prod;
                            res = Arrays.asList(arr[i], arr[j], arr[k]);
                        }
                    }
                }
            }
        }
        return res;
    }

    public static void main(String[] args) {
        int[] arr = {6, 7, 8, 1, 2, 3, 9, 10};
        System.out.println(maxProductSubsequence(arr));
    }
}
Python
def maxProductSubsequence(arr):
    n = len(arr)
    maxProd = -1
    res = []

    # Try all triplets i < j < k with arr[i] < arr[j] < arr[k]
    for i in range(n):
        for j in range(i + 1, n):
            for k in range(j + 1, n):
                if arr[i] < arr[j] < arr[k]:
                    prod = arr[i] * arr[j] * arr[k]
                    if prod > maxProd:
                        maxProd = prod
                        res = [arr[i], arr[j], arr[k]]
    return res

if __name__ == "__main__":
    arr = [6, 7, 8, 1, 2, 3, 9, 10]
    print(maxProductSubsequence(arr))
C#
using System;
using System.Collections.Generic;

class GfG {

    static List<int> maxProductSubsequence(int[] arr) {
        int n = arr.Length;
        long maxProd = -1;
        List<int> res = new List<int>();

        // Try all triplets i < j < k with arr[i] < arr[j] < arr[k]
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                for (int k = j + 1; k < n; k++) {
                    if (arr[i] < arr[j] && arr[j] < arr[k]) {
                        long prod = (long) arr[i] * arr[j] * arr[k];
                        if (prod > maxProd) {
                            maxProd = prod;
                            res = new List<int> {arr[i], arr[j], arr[k]};
                        }
                    }
                }
            }
        }
        return res;
    }

    static void Main() {
        int[] arr = {6, 7, 8, 1, 2, 3, 9, 10};
        Console.WriteLine(string.Join(", ", maxProductSubsequence(arr)));
    }
}
JavaScript
function maxProductSubsequence(arr) {
    const n = arr.length;
    let maxProd = -1;
    let res = [];

    // Try all triplets i < j < k with arr[i] < arr[j] < arr[k]
    for (let i = 0; i < n; i++) {
        for (let j = i + 1; j < n; j++) {
            for (let k = j + 1; k < n; k++) {
                if (arr[i] < arr[j] && arr[j] < arr[k]) {
                    const prod = arr[i] * arr[j] * arr[k];
                    if (prod > maxProd) {
                        maxProd = prod;
                        res = [arr[i], arr[j], arr[k]];
                    }
                }
            }
        }
    }
    return res;
}

// Driver code
const arr = [6, 7, 8, 1, 2, 3, 9, 10];
console.log(maxProductSubsequence(arr));

Output
2200

[Better Approach] Using Middle Element - O(n^2) Time and O(1) Space

Instead of trying all triplets, fix each element as the middle element and scan left for the largest smaller element and scan right for the largest greater element. This reduces one loop giving O(n^2).

  • For each element arr[j] as middle, scan left to find largest element strictly less than arr[j].
  • Scan right to find largest element strictly greater than arr[j].
  • Compute product and update maximum.
  • If no valid triplet found return empty list.
C++
#include <bits/stdc++.h>
using namespace std;

vector<int> maxProductSubsequence(vector<int>& arr) {
    int n = arr.size();
    long long maxProd = -1;
    vector<int> res;

    for (int j = 1; j < n - 1; j++) {

        // Find largest element strictly less than arr[j] from left
        int left = -1;
        for (int i = 0; i < j; i++)
            if (arr[i] < arr[j])
                left = max(left, arr[i]);

        // Find largest element strictly greater than arr[j] from right
        int right = -1;
        for (int k = j + 1; k < n; k++)
            if (arr[k] > arr[j])
                right = max(right, arr[k]);

        // Update result if valid triplet found
        if (left != -1 && right != -1) {
            long long prod = (1LL * left) * arr[j] * right;
            if (prod > maxProd) {
                maxProd = prod;
                res = {left, arr[j], right};
            }
        }
    }
    return res;
}

int main() {
    vector<int> arr = {6, 7, 8, 1, 2, 3, 9, 10};
    vector<int> res = maxProductSubsequence(arr);
    for (int x : res) cout << x << " ";
    return 0;
}
Java
import java.util.*;

class GfG {

    static List<Integer> maxProductSubsequence(int[] arr) {
        int n = arr.length;
        long maxProd = -1;
        List<Integer> res = new ArrayList<>();

        for (int j = 1; j < n - 1; j++) {

            // Find largest element strictly less than arr[j] from left
            int left = -1;
            for (int i = 0; i < j; i++)
                if (arr[i] < arr[j])
                    left = Math.max(left, arr[i]);

            // Find largest element strictly greater than arr[j] from right
            int right = -1;
            for (int k = j + 1; k < n; k++)
                if (arr[k] > arr[j])
                    right = Math.max(right, arr[k]);

            // Update result if valid triplet found
            if (left != -1 && right != -1) {
                long prod = (long) left * arr[j] * right;
                if (prod > maxProd) {
                    maxProd = prod;
                    res = Arrays.asList(left, arr[j], right);
                }
            }
        }
        return res;
    }

    public static void main(String[] args) {
        int[] arr = {6, 7, 8, 1, 2, 3, 9, 10};
        System.out.println(maxProductSubsequence(arr));
    }
}
Python
def maxProductSubsequence(arr):
    n = len(arr)
    maxProd = -1
    res = []

    for j in range(1, n - 1):

        # Find largest element strictly less than arr[j] from left
        left = -1
        for i in range(j):
            if arr[i] < arr[j]:
                left = max(left, arr[i])

        # Find largest element strictly greater than arr[j] from right
        right = -1
        for k in range(j + 1, n):
            if arr[k] > arr[j]:
                right = max(right, arr[k])

        # Update result if valid triplet found
        if left != -1 and right != -1:
            prod = left * arr[j] * right
            if prod > maxProd:
                maxProd = prod
                res = [left, arr[j], right]

    return res

if __name__ == "__main__":
    arr = [6, 7, 8, 1, 2, 3, 9, 10]
    print(maxProductSubsequence(arr))
C#
using System;
using System.Collections.Generic;

class GfG {

    static List<int> maxProductSubsequence(int[] arr) {
        int n = arr.Length;
        long maxProd = -1;
        List<int> res = new List<int>();

        for (int j = 1; j < n - 1; j++) {

            // Find largest element strictly less than arr[j] from left
            int left = -1;
            for (int i = 0; i < j; i++)
                if (arr[i] < arr[j])
                    left = Math.Max(left, arr[i]);

            // Find largest element strictly greater than arr[j] from right
            int right = -1;
            for (int k = j + 1; k < n; k++)
                if (arr[k] > arr[j])
                    right = Math.Max(right, arr[k]);

            // Update result if valid triplet found
            if (left != -1 && right != -1) {
                long prod = (long) left * arr[j] * right;
                if (prod > maxProd) {
                    maxProd = prod;
                    res = new List<int> {left, arr[j], right};
                }
            }
        }
        return res;
    }

    static void Main() {
        int[] arr = {6, 7, 8, 1, 2, 3, 9, 10};
        Console.WriteLine(string.Join(", ", maxProductSubsequence(arr)));
    }
}
JavaScript
function maxProductSubsequence(arr) {
    const n = arr.length;
    let maxProd = -1;
    let res = [];

    for (let j = 1; j < n - 1; j++) {

        // Find largest element strictly less than arr[j] from left
        let left = -1;
        for (let i = 0; i < j; i++)
            if (arr[i] < arr[j])
                left = Math.max(left, arr[i]);

        // Find largest element strictly greater than arr[j] from right
        let right = -1;
        for (let k = j + 1; k < n; k++)
            if (arr[k] > arr[j])
                right = Math.max(right, arr[k]);

        // Update result if valid triplet found
        if (left !== -1 && right !== -1) {
            const prod = left * arr[j] * right;
            if (prod > maxProd) {
                maxProd = prod;
                res = [left, arr[j], right];
            }
        }
    }
    return res;
}

// Driver code
const arr = [6, 7, 8, 1, 2, 3, 9, 10];
console.log(maxProductSubsequence(arr));

Output
8 9 10 

[Expected Approach] Using Sorted Set / Fenwick Tree - O(n log n) Time and O(n) Space

For each element as the middle element, instead of scanning left in O(n) we find the largest smaller element in O(log n) - using a sorted set in C++/Java, and a Fenwick tree over coordinate-compressed values in Python/JavaScript/(languages without a built-in sorted set). For the right side a single right to left pass tracking the running maximum gives the largest greater element in O(1).

  • Traverse left to right maintaining a sorted set (or Fenwick tree). For each element query the largest element strictly less than it - that's left[i].
  • Traverse right to left maintaining a running maximum. For each element if running max is greater than it - that's right[i].
  • For each index as middle element compute left[i] * arr[i] * right[i] and track maximum.
  • Return the triplet with maximum product.
C++
#include <bits/stdc++.h>
using namespace std;

vector<int> maxProductSubsequence(vector<int>& arr) {
    int n = arr.size();
    vector<int> left(n, -1), right(n, -1);

    // Find greatest smaller element on left for every index
    set<int> st;
    for (int i = 0; i < n; i++) {
        auto it = st.lower_bound(arr[i]);
        if (it != st.begin()) {
            --it;
            left[i] = *it;
        }
        st.insert(arr[i]);
    }

    // Find greatest element on right for every index
    int maxRight = arr[n - 1];
    for (int i = n - 2; i >= 0; i--) {
        if (arr[i] < maxRight)
            right[i] = maxRight;
        maxRight = max(maxRight, arr[i]);
    }

    // Find maximum product using middle element
    long long maxProd = -1;
    vector<int> res;
    for (int i = 0; i < n; i++) {
        if (left[i] != -1 && right[i] != -1) {
            long long prod = (1LL * left[i]) * arr[i] * right[i];
            if (prod > maxProd) {
                maxProd = prod;
                res = {left[i], arr[i], right[i]};
            }
        }
    }
    return res;
}

int main() {
    vector<int> arr = {6, 7, 8, 1, 2, 3, 9, 10};
    vector<int> res = maxProductSubsequence(arr);
    for (int x : res) cout << x << " ";
    return 0;
}
Java
import java.util.*;

class GfG {

    static List<Integer> maxProductSubsequence(int[] arr) {
        int n = arr.length;
        int[] left = new int[n];
        int[] right = new int[n];
        Arrays.fill(left, -1);
        Arrays.fill(right, -1);

        // Find greatest smaller element on left for every index
        TreeSet<Integer> set = new TreeSet<>();
        for (int i = 0; i < n; i++) {
            Integer smaller = set.lower(arr[i]);
            if (smaller != null)
                left[i] = smaller;
            set.add(arr[i]);
        }

        // Find greatest element on right for every index
        int maxRight = arr[n - 1];
        for (int i = n - 2; i >= 0; i--) {
            if (arr[i] < maxRight)
                right[i] = maxRight;
            maxRight = Math.max(maxRight, arr[i]);
        }

        // Find maximum product using middle element
        long maxProd = -1;
        List<Integer> res = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            if (left[i] != -1 && right[i] != -1) {
                long prod = (long) left[i] * arr[i] * right[i];
                if (prod > maxProd) {
                    maxProd = prod;
                    res = Arrays.asList(left[i], arr[i], right[i]);
                }
            }
        }
        return res;
    }

    public static void main(String[] args) {
        int[] arr = {6, 7, 8, 1, 2, 3, 9, 10};
        System.out.println(maxProductSubsequence(arr));
    }
}
Python
def maxProductSubsequence(arr):
    n = len(arr)

    # Coordinate compress values to ranks for Fenwick tree indexing
    sortedVals = sorted(set(arr))
    rank = {v: i + 1 for i, v in enumerate(sortedVals)}
    m = len(sortedVals)

    # Fenwick tree for prefix maximum, -1 means no value seen
    fen = [-1] * (m + 1)

    def update(pos, val):
        while pos <= m:
            fen[pos] = max(fen[pos], val)
            pos += pos & (-pos)

    def query(pos):
        res = -1
        while pos > 0:
            res = max(res, fen[pos])
            pos -= pos & (-pos)
        return res

    # Find greatest smaller element on left for every index using Fenwick tree
    left = [-1] * n
    for i in range(n):
        r = rank[arr[i]]
        if r > 1:
            left[i] = query(r - 1)
        update(r, arr[i])

    # Find greatest element on right for every index
    right = [-1] * n
    maxRight = arr[n - 1]
    for i in range(n - 2, -1, -1):
        if arr[i] < maxRight:
            right[i] = maxRight
        maxRight = max(maxRight, arr[i])

    # Find maximum product using middle element
    maxProd = -1
    res = []
    for i in range(n):
        if left[i] != -1 and right[i] != -1:
            prod = left[i] * arr[i] * right[i]
            if prod > maxProd:
                maxProd = prod
                res = [left[i], arr[i], right[i]]
    return res

if __name__ == "__main__":
    arr = [6, 7, 8, 1, 2, 3, 9, 10]
    print(maxProductSubsequence(arr))
C#
using System;
using System.Collections.Generic;

class GfG {

    static List<int> maxProductSubsequence(int[] arr) {
        int n = arr.Length;

        // Coordinate compress values to ranks for Fenwick tree indexing
        List<int> sortedVals = new List<int>(new HashSet<int>(arr));
        sortedVals.Sort();
        Dictionary<int, int> rank = new Dictionary<int, int>();
        for (int i = 0; i < sortedVals.Count; i++)
            rank[sortedVals[i]] = i + 1;
        int m = sortedVals.Count;

        // Fenwick tree for prefix maximum, -1 means no value seen
        int[] fen = new int[m + 1];
        for (int i = 0; i <= m; i++) fen[i] = -1;

        void Update(int pos, int val) {
            while (pos <= m) {
                fen[pos] = Math.Max(fen[pos], val);
                pos += pos & (-pos);
            }
        }

        int Query(int pos) {
            int res = -1;
            while (pos > 0) {
                res = Math.Max(res, fen[pos]);
                pos -= pos & (-pos);
            }
            return res;
        }

        // Find greatest smaller element on left for every index using Fenwick tree
        int[] left = new int[n];
        for (int i = 0; i < n; i++) {
            int r = rank[arr[i]];
            left[i] = (r > 1) ? Query(r - 1) : -1;
            Update(r, arr[i]);
        }

        // Find greatest element on right for every index
        int[] right = new int[n];
        for (int i = 0; i < n; i++) right[i] = -1;

        int maxRight = arr[n - 1];
        for (int i = n - 2; i >= 0; i--) {
            right[i] = (arr[i] < maxRight) ? maxRight : -1;
            maxRight = Math.Max(maxRight, arr[i]);
        }

        // Find maximum product using middle element
        long maxProd = -1;
        List<int> res = new List<int>();
        for (int i = 0; i < n; i++) {
            if (left[i] != -1 && right[i] != -1) {
                long prod = (long) left[i] * arr[i] * right[i];
                if (prod > maxProd) {
                    maxProd = prod;
                    res = new List<int> { left[i], arr[i], right[i] };
                }
            }
        }
        return res;
    }

    static void Main() {
        int[] arr = {6, 7, 8, 1, 2, 3, 9, 10};
        Console.WriteLine(string.Join(", ", maxProductSubsequence(arr)));
    }
}
JavaScript
function maxProductSubsequence(arr) {
    const n = arr.length;

    // Coordinate compress values to ranks for Fenwick tree indexing
    const sortedVals = [...new Set(arr)].sort((a, b) => a - b);
    const rank = new Map();
    sortedVals.forEach((v, i) => rank.set(v, i + 1));
    const m = sortedVals.length;

    // Fenwick tree for prefix maximum, -1 means no value seen
    const fen = new Array(m + 1).fill(-1);

    const update = (pos, val) => {
        while (pos <= m) {
            fen[pos] = Math.max(fen[pos], val);
            pos += pos & (-pos);
        }
    };

    const query = (pos) => {
        let res = -1;
        while (pos > 0) {
            res = Math.max(res, fen[pos]);
            pos -= pos & (-pos);
        }
        return res;
    };

    // Find greatest smaller element on left for every index using Fenwick tree
    const left = new Array(n).fill(-1);
    for (let i = 0; i < n; i++) {
        const r = rank.get(arr[i]);
        if (r > 1)
            left[i] = query(r - 1);
        update(r, arr[i]);
    }

    // Find greatest element on right for every index
    const right = new Array(n).fill(-1);
    let maxRight = arr[n - 1];
    for (let i = n - 2; i >= 0; i--) {
        if (arr[i] < maxRight)
            right[i] = maxRight;
        maxRight = Math.max(maxRight, arr[i]);
    }

    // Find maximum product using middle element
    let maxProd = -1;
    let res = [];
    for (let i = 0; i < n; i++) {
        if (left[i] !== -1 && right[i] !== -1) {
            const prod = left[i] * arr[i] * right[i];
            if (prod > maxProd) {
                maxProd = prod;
                res = [left[i], arr[i], right[i]];
            }
        }
    }
    return res;
}

// Driver code
const arr = [6, 7, 8, 1, 2, 3, 9, 10];
console.log(maxProductSubsequence(arr));

Output
8 9 10 
Comment