Longest Geometric Progression

Last Updated : 26 Jul, 2026

Given an array arr[] of positive integers, find the length of the longest geometric progression (GP) that can be formed by rearranging elements from the array. The common ratio of the GP must be an integer (ratio ≥ 1 is allowed, including a GP of equal elements).

Examples: 

Input: arr[] = [2, 4, 3]
Output: 2
Explanation: The longest geometric progression is [2, 4], with common ratio 2.

Input: arr[] = [5, 7, 15, 10, 20, 29]
Output: 3
Explanation: The longest geometric progression is [5, 10, 20], with common ratio 2.

Try It Yourself
redirect icon

[Naive Approach] Check Every Pair as First Two Terms - O(n ^ 2 * L) Time and O(n) Space

The idea is to consider every pair of elements as the first two terms of a geometric progression. If their ratio is an integer, keep multiplying by the ratio and check whether the next term exists in the array. Store all elements in a hash set for fast lookup and update the maximum GP length found.

Working of Approach:

  • Store all array elements in a hash set.
  • Try every pair of elements as the first two terms of a GP.
  • If the ratio is an integer, keep generating the next terms.
  • Count the length while the next term exists in the set.
  • Return the maximum length obtained.
C++
#include <bits/stdc++.h>
using namespace std;

int lenOfLongestGP(vector<int> &arr)
{
    int n = arr.size();

    if (n == 0)
        return 0;

    // Store all elements for fast lookup
    unordered_set<int> st(arr.begin(), arr.end());

    // Store frequency to handle ratio = 1
    unordered_map<int, int> freq;

    int res = 1;

    // Count frequency of every element
    for (int x : arr)
    {
        freq[x]++;
        res = max(res, freq[x]);
    }

    // Try every pair as the first two terms of a GP
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {

            if (i == j)
                continue;

            // Ratio must be an integer
            if (arr[j] % arr[i] != 0)
                continue;

            int r = arr[j] / arr[i];

            // Ratio 1 is already handled
            if (r <= 1)
                continue;

            int len = 2;
            int term = arr[j] * r;

            // Keep generating the next GP terms
            while (term <= 40000 && st.count(term))
            {
                len++;

                // Prevent integer overflow
                if (term > 40000 / r)
                    break;

                term *= r;
            }

            res = max(res, len);
        }
    }

    return res;
}

int main()
{
    vector<int> arr = {5, 7, 15, 10, 20, 29};

    cout << lenOfLongestGP(arr);

    return 0;
}
Java
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class GFG {
    public static int lenOfLongestGP(int[] arr)
    {
        int n = arr.length;

        if (n == 0)
            return 0;

        // Store all elements for fast lookup
        Set<Integer> st = new HashSet<>();
        for (int x : arr) {
            st.add(x);
        }

        // Store frequency to handle ratio = 1
        Map<Integer, Integer> freq = new HashMap<>();

        int res = 1;

        // Count frequency of every element
        for (int x : arr) {
            freq.put(x, freq.getOrDefault(x, 0) + 1);
            res = Math.max(res, freq.get(x));
        }

        // Try every pair as the first two terms of a GP
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {

                if (i == j)
                    continue;

                // Ratio must be an integer
                if (arr[j] % arr[i] != 0)
                    continue;

                int r = arr[j] / arr[i];

                // Ratio 1 is already handled
                if (r <= 1)
                    continue;

                int len = 2;
                int term = arr[j] * r;

                // Keep generating the next GP terms
                while (term <= 40000 && st.contains(term)) {
                    len++;

                    // Prevent integer overflow
                    if (term > 40000 / r)
                        break;

                    term *= r;
                }

                res = Math.max(res, len);
            }
        }

        return res;
    }

    public static void main(String[] args)
    {
        int[] arr = { 5, 7, 15, 10, 20, 29 };
        System.out.println(lenOfLongestGP(arr));
    }
}
Python
from collections import defaultdict


def lenOfLongestGP(arr):
    n = len(arr)

    if n == 0:
        return 0

    # Store all elements for fast lookup
    st = set(arr)

    # Store frequency to handle ratio = 1
    freq = defaultdict(int)

    res = 1

    # Count frequency of every element
    for x in arr:
        freq[x] += 1
        res = max(res, freq[x])

    # Try every pair as the first two terms of a GP
    for i in range(n):
        for j in range(n):

            if i == j:
                continue

            # Ratio must be an integer
            if arr[j] % arr[i] != 0:
                continue

            r = arr[j] // arr[i]

            # Ratio 1 is already handled
            if r <= 1:
                continue

            len_gp = 2
            term = arr[j] * r

            # Keep generating the next GP terms
            while term <= 40000 and term in st:
                len_gp += 1

                # Prevent integer overflow
                if term > 40000 // r:
                    break

                term *= r

            res = max(res, len_gp)

    return res


if __name__ == '__main__':
    arr = [5, 7, 15, 10, 20, 29]
    print(lenOfLongestGP(arr))
C#
using System;
using System.Collections.Generic;

public class GFG {
    public static int lenOfLongestGP(int[] arr)
    {
        int n = arr.Length;

        if (n == 0)
            return 0;

        // Store all elements for fast lookup
        HashSet<int> st = new HashSet<int>(arr);

        // Store frequency to handle ratio = 1
        Dictionary<int, int> freq
            = new Dictionary<int, int>();

        int res = 1;

        // Count frequency of every element
        foreach(int x in arr)
        {
            if (freq.ContainsKey(x))
                freq[x]++;
            else
                freq[x] = 1;

            res = Math.Max(res, freq[x]);
        }

        // Try every pair as the first two terms of a GP
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (i == j)
                    continue;

                // Ratio must be an integer
                if (arr[j] % arr[i] != 0)
                    continue;

                int r = arr[j] / arr[i];

                // Ratio 1 is already handled
                if (r <= 1)
                    continue;

                int len = 2;
                int term = arr[j] * r;

                // Keep generating the next GP terms
                while (term <= 40000 && st.Contains(term)) {
                    len++;

                    // Prevent integer overflow
                    if (term > 40000 / r)
                        break;

                    term *= r;
                }

                res = Math.Max(res, len);
            }
        }

        return res;
    }

    public static void Main()
    {
        int[] arr = { 5, 7, 15, 10, 20, 29 };
        Console.WriteLine(lenOfLongestGP(arr));
    }
}
JavaScript
function lenOfLongestGP(arr)
{
    const n = arr.length;

    if (n === 0)
        return 0;

    // Store all elements for fast lookup
    const st = new Set(arr);

    // Store frequency to handle ratio = 1
    const freq = new Map();

    let res = 1;

    // Count frequency of every element
    for (const x of arr) {
        if (freq.has(x)) {
            freq.set(x, freq.get(x) + 1);
        }
        else {
            freq.set(x, 1);
        }
        res = Math.max(res, freq.get(x));
    }

    // Try every pair as the first two terms of a GP
    for (let i = 0; i < n; i++) {
        for (let j = 0; j < n; j++) {

            if (i === j)
                continue;

            // Ratio must be an integer
            if (arr[j] % arr[i] !== 0)
                continue;

            const r = Math.floor(arr[j] / arr[i]);

            // Ratio 1 is already handled
            if (r <= 1)
                continue;

            let len = 2;
            let term = arr[j] * r;

            // Keep generating the next GP terms
            while (term <= 40000 && st.has(term)) {
                len++;

                // Prevent integer overflow
                if (term > 40000 / r)
                    break;

                term *= r;
            }

            res = Math.max(res, len);
        }
    }

    return res;
}

// Driver Code
const arr = [ 5, 7, 15, 10, 20, 29 ];
console.log(lenOfLongestGP(arr));

Output
3

Time Complexity: O(n ^ 2 · L), where L is the maximum GP length.
Space Complexity: O(n)

[Expected Approach] Using Dynamic Programming on Sorted Array - O(n ^ 2 * log n) Time and O(n ^ 2) Space

The idea is to sort the array and use dynamic programming. Let dp[i][j] denote the length of the longest geometric progression ending with arr[i] as second last and arr[j] as last element. For every pair, compute the required previous term using pred = (arr[i] * arr[i]) / arr[j] and extend the GP if such a term exists.

Working of Approach:

  • Sort the array in increasing order.
  • Store the indices of every value to handle duplicates.
  • Let dp[i][j] store the GP length ending at arr[i] and arr[j].
  • Find the required previous term and extend the GP if it exists.
  • Return the maximum value in the DP table.

Let us understand with an example:
Input: arr[] = [5, 7, 15, 10, 20, 29]

  • First, sort the array to get [5, 7, 10, 15, 20, 29].
  • Consider every pair of elements as the last two terms of a possible GP.
  • For each pair, compute the required previous term and check whether it exists before the current pair.
  • If the previous term exists, extend the existing GP using the DP table; otherwise, start a new GP of length 2.
  • Continue this process for all pairs while keeping track of the maximum GP length found.
  • The longest geometric progression is {5, 10, 20}, so the output is 3.
C++
#include <bits/stdc++.h>
using namespace std;

int lenOfLongestGP(vector<int> &arr)
{
    int n = arr.size();

    // 0 or 1 element is trivially its own GP
    if (n <= 1)
        return n;

    // GP terms must be considered in increasing order
    sort(arr.begin(), arr.end());

    // positions[val] = sorted indices where 'val' occurs,
    // needed to correctly handle duplicate elements
    unordered_map<int, vector<int>> positions;
    for (int idx = 0; idx < n; idx++)
        positions[arr[idx]].push_back(idx);

    // dp[i][j] = length of LGP with arr[i], arr[j] as its
    // last two terms (i < j), valid only for integer ratio
    vector<vector<int>> dp(n, vector<int>(n, 0));

    // A single element is always a valid GP of length 1
    int res = 1;

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

            // Ratio arr[j]/arr[i] must be an integer,
            // else this pair can never form a valid GP
            if (arr[j] % arr[i] != 0)
                continue;

            // Predecessor value needed to extend the chain:
            // pred * arr[j] = arr[i] * arr[i]
            int num = arr[i] * arr[i];
            int len = 2; // fallback: fresh GP of length 2

            if (num % arr[j] == 0)
            {
                int predVal = num / arr[j];
                auto it = positions.find(predVal);

                if (it != positions.end())
                {
                    // largest index strictly less than i
                    // holding value predVal
                    vector<int> &v = it->second;
                    int pos = upper_bound(v.begin(), v.end(), i - 1) - v.begin() - 1;

                    if (pos >= 0)
                        len = dp[v[pos]][i] + 1;
                }
            }

            dp[i][j] = len;
            res = max(res, len);
        }
    }

    return res;
}

int main()
{
    vector<int> arr = {5, 7, 15, 10, 20, 29};

    cout << lenOfLongestGP(arr);

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

public class GFG {
    public static int lenOfLongestGP(int[] arr)
    {
        int n = arr.length;

        // 0 or 1 element is trivially its own GP
        if (n <= 1)
            return n;

        // GP terms must be considered in increasing order
        Arrays.sort(arr);

        // positions[val] = sorted indices where 'val'
        // occurs, needed to correctly handle duplicate
        // elements
        Map<Integer, List<Integer> > positions
            = new HashMap<>();
        for (int idx = 0; idx < n; idx++)
            positions
                .computeIfAbsent(arr[idx],
                                 k -> new ArrayList<>())
                .add(idx);

        // dp[i][j] = length of LGP with arr[i], arr[j] as
        // its last two terms (i < j), valid only for
        // integer ratio
        int[][] dp = new int[n][n];

        // A single element is always a valid GP of length 1
        int res = 1;

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

                // Ratio arr[j]/arr[i] must be an integer,
                // else this pair can never form a valid GP
                if (arr[j] % arr[i] != 0)
                    continue;

                // Predecessor value needed to extend the
                // chain: pred * arr[j] = arr[i] * arr[i]
                int num = arr[i] * arr[i];
                int len
                    = 2; // fallback: fresh GP of length 2

                if (num % arr[j] == 0) {
                    int predVal = num / arr[j];
                    List<Integer> v
                        = positions.get(predVal);

                    if (v != null) {
                        // largest index strictly less than
                        // i holding value predVal
                        int pos = Collections.binarySearch(
                            v, i - 1);
                        if (pos < 0)
                            pos = -pos - 2;

                        if (pos >= 0)
                            len = dp[v.get(pos)][i] + 1;
                    }
                }

                dp[i][j] = len;
                res = Math.max(res, len);
            }
        }

        return res;
    }

    public static void main(String[] args)
    {
        int[] arr = { 5, 7, 15, 10, 20, 29 };
        System.out.println(lenOfLongestGP(arr));
    }
}
Python
from collections import defaultdict


def lenOfLongestGP(arr):
    n = len(arr)

    # 0 or 1 element is trivially its own GP
    if n <= 1:
        return n

    # GP terms must be considered in increasing order
    arr.sort()

    # positions[val] = sorted indices where 'val' occurs,
    # needed to correctly handle duplicate elements
    positions = defaultdict(list)
    for idx in range(n):
        positions[arr[idx]].append(idx)

    # dp[i][j] = length of LGP with arr[i], arr[j] as its
    # last two terms (i < j), valid only for integer ratio
    dp = [[0] * n for _ in range(n)]

    # A single element is always a valid GP of length 1
    res = 1

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

            # Ratio arr[j]/arr[i] must be an integer,
            # else this pair can never form a valid GP
            if arr[j] % arr[i] != 0:
                continue

            # Predecessor value needed to extend the chain:
            # pred * arr[j] = arr[i] * arr[i]
            num = arr[i] * arr[i]
            len_ = 2  # fallback: fresh GP of length 2

            if num % arr[j] == 0:
                predVal = num // arr[j]
                if predVal in positions:
                    v = positions[predVal]
                    pos = bisect_right(v, i - 1) - 1

                    if pos >= 0:
                        len_ = dp[v[pos]][i] + 1

            dp[i][j] = len_
            res = max(res, len_)

    return res


def bisect_right(a, x):
    lo = 0
    hi = len(a)
    while lo < hi:
        mid = (lo + hi) // 2
        if a[mid] <= x:
            lo = mid + 1
        else:
            hi = mid
    return lo


if __name__ == '__main__':
    arr = [5, 7, 15, 10, 20, 29]
    print(lenOfLongestGP(arr))
C#
using System;
using System.Collections.Generic;

class GFG {
    static int lenOfLongestGP(int[] arr)
    {
        int n = arr.Length;

        // 0 or 1 element is trivially its own GP
        if (n <= 1)
            return n;

        // GP terms must be considered in increasing order
        Array.Sort(arr);

        // positions[val] = sorted indices where 'val'
        // occurs, needed to correctly handle duplicate
        // elements
        Dictionary<int, List<int> > positions
            = new Dictionary<int, List<int> >();
        for (int idx = 0; idx < n; idx++) {
            if (!positions.ContainsKey(arr[idx]))
                positions[arr[idx]] = new List<int>();
            positions[arr[idx]].Add(idx);
        }

        // dp[i][j] = length of LGP with arr[i], arr[j] as
        // its last two terms (i < j), valid only for
        // integer ratio
        int[, ] dp = new int[n, n];

        // A single element is always a valid GP of length 1
        int res = 1;

        for (int j = 1; j < n; j++) {
            for (int i = 0; i < j; i++) {
                // Ratio arr[j]/arr[i] must be an integer,
                // else this pair can never form a valid GP
                if (arr[j] % arr[i] != 0)
                    continue;

                // Predecessor value needed to extend the
                // chain: pred * arr[j] = arr[i] * arr[i]
                int num = arr[i] * arr[i];
                int len
                    = 2; // fallback: fresh GP of length 2

                if (num % arr[j] == 0) {
                    int predVal = num / arr[j];
                    if (positions.ContainsKey(predVal)) {
                        List<int> v = positions[predVal];
                        int pos = v.BinarySearch(i - 1);
                        if (pos < 0)
                            pos = ~pos - 1;
                        if (pos >= 0)
                            len = dp[v[pos], i] + 1;
                    }
                }

                dp[i, j] = len;
                res = Math.Max(res, len);
            }
        }

        return res;
    }

    static void Main()
    {
        int[] arr = { 5, 7, 15, 10, 20, 29 };

        Console.WriteLine(lenOfLongestGP(arr));
    }
}
JavaScript
function lenOfLongestGP(arr)
{
    let n = arr.length;

    // 0 or 1 element is trivially its own GP
    if (n <= 1)
        return n;

    // GP terms must be considered in increasing order
    arr.sort((a, b) => a - b);

    // positions[val] = sorted indices where 'val' occurs,
    // needed to correctly handle duplicate elements
    let positions = new Map();
    for (let idx = 0; idx < n; idx++) {
        if (!positions.has(arr[idx])) {
            positions.set(arr[idx], []);
        }
        positions.get(arr[idx]).push(idx);
    }

    // dp[i][j] = length of LGP with arr[i], arr[j] as its
    // last two terms (i < j), valid only for integer ratio
    let dp
        = Array.from({length : n}, () => Array(n).fill(0));

    // A single element is always a valid GP of length 1
    let res = 1;

    for (let j = 1; j < n; j++) {
        for (let i = 0; i < j; i++) {
            // Ratio arr[j]/arr[i] must be an integer,
            // else this pair can never form a valid GP
            if (arr[j] % arr[i] != 0)
                continue;

            // Predecessor value needed to extend the chain:
            // pred * arr[j] = arr[i] * arr[i]
            let num = arr[i] * arr[i];
            let len = 2; // fallback: fresh GP of length 2

            if (num % arr[j] == 0) {
                let predVal = num / arr[j];
                if (positions.has(predVal)) {
                    let v = positions.get(predVal);
                    let pos
                        = v.filter(val => val < i).length
                          - 1;
                    if (pos >= 0)
                        len = dp[v[pos]][i] + 1;
                }
            }

            dp[i][j] = len;
            res = Math.max(res, len);
        }
    }

    return res;
}

// Driver Code
let arr = [ 5, 7, 15, 10, 20, 29 ];
console.log(lenOfLongestGP(arr));

Output
3

Time Complexity: O(n ^ 2 * log n), where n ^ 2 comes from checking all pairs of elements and log n comes from the binary search (upper_bound) used to find the predecessor for each pair.
Space Complexity: O(n ^ 2), where O(n ^ 2) space is required for the DP table and O(n) for storing the positions of each value. Since the DP table dominates, the overall auxiliary space is O(n ^ 2).

Comment