Given a strictly increasing integer array arr[]. The subsequence of the given array is called good if it satisfies the following two conditions:
- The elements of the subsequence should be in strictly increasing order.
- No two adjacent elements should be coprime.
Find the length of the longest good subsequence.
Examples:
Input: arr[] = [2, 3, 6, 9, 10]
Output: 3
Explanation: Longest good subsequence is [2, 6, 10]
Input: arr[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Ouput : 5
Explanation: Longest good subsequence is [2, 4, 6, 8, 10]
[Naive Approach] Try every possible subsequence - O(2^n) Time and O(n) Space
The idea is to try every possible subsequence of the array and checks which ones satisfy the conditions. For each subsequence, we verify that all adjacent elements are not coprime by computing their gcd. Since subsequences can be formed by picking or not picking every element, there are 2n possible combinations. We track the longest valid subsequence among all these. Although this brute-force approach guarantees correctness, it is extremely slow for larger n because the number of subsequences grows exponentially. This approach is useful only for very small input sizes.
C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// compute gcd
int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
// check if subsequence is good
bool isGood(const vector<int>& seq) {
// check adjacent pairs
for (int i = 0; i < (int)seq.size() - 1; i++) {
if (gcd(seq[i], seq[i+1]) == 1)
return false;
}
return true;
}
// brute force: try all subsequences
int maxGoodSubseq(const vector<int>& arr) {
int n = arr.size();
int maxLen = 0;
for (int mask = 1; mask < (1 << n); mask++) {
vector<int> subseq;
for (int i = 0; i < n; i++) {
if (mask & (1 << i))
subseq.push_back(arr[i]);
}
if (isGood(subseq))
maxLen = max(maxLen, (int)subseq.size());
}
return maxLen;
}
int main() {
vector<int> arr = {2, 3, 6, 9, 10};
cout << maxGoodSubseq(arr) << endl;
return 0;
}
Java
class GFG {
// compute gcd
static int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
// check if subsequence is good
static boolean isGood(java.util.ArrayList<Integer> seq) {
for (int i = 0; i < seq.size() - 1; i++) {
if (gcd(seq.get(i), seq.get(i + 1)) == 1)
return false;
}
return true;
}
// brute force: try all subsequences
static int maxGoodSubseq(int[] arr) {
int n = arr.length;
int maxLen = 0;
for (int mask = 1; mask < (1 << n); mask++) {
java.util.ArrayList<Integer> subseq = new java.util.ArrayList<>();
for (int i = 0; i < n; i++) {
if ((mask & (1 << i)) != 0)
subseq.add(arr[i]);
}
if (isGood(subseq))
maxLen = Math.max(maxLen, subseq.size());
}
return maxLen;
}
public static void main(String[] args) {
int[] arr = {2, 3, 6, 9, 10};
System.out.println(maxGoodSubseq(arr));
}
}
Python
# compute gcd
def gcd(a, b):
return a if b == 0 else gcd(b, a % b)
# check if subsequence is good
def isGood(seq):
for i in range(len(seq) - 1):
if gcd(seq[i], seq[i+1]) == 1:
return False
return True
# brute force: try all subsequences
def maxGoodSubseq(arr):
n = len(arr)
maxLen = 0
for mask in range(1, 1 << n):
subseq = []
for i in range(n):
if mask & (1 << i):
subseq.append(arr[i])
if isGood(subseq):
maxLen = max(maxLen, len(subseq))
return maxLen
if __name__ == "__main__":
arr = [2, 3, 6, 9, 10]
print(maxGoodSubseq(arr))
C#
using System;
using System.Collections.Generic;
class GFG {
// compute gcd
static int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
// check if subsequence is good
static bool isGood(List<int> seq) {
for (int i = 0; i < seq.Count - 1; i++) {
if (gcd(seq[i], seq[i + 1]) == 1)
return false;
}
return true;
}
// brute force: try all subsequences
static int maxGoodSubseq(int[] arr) {
int n = arr.Length;
int maxLen = 0;
for (int mask = 1; mask < (1 << n); mask++) {
List<int> subseq = new List<int>();
for (int i = 0; i < n; i++) {
if ((mask & (1 << i)) != 0)
subseq.Add(arr[i]);
}
if (isGood(subseq))
maxLen = Math.Max(maxLen, subseq.Count);
}
return maxLen;
}
static void Main() {
int[] arr = {2, 3, 6, 9, 10};
Console.WriteLine(maxGoodSubseq(arr));
}
}
JavaScript
// compute gcd
function gcd(a, b) {
return b === 0 ? a : gcd(b, a % b);
}
// check if subsequence is good
function isGood(seq) {
for (let i = 0; i < seq.length - 1; i++) {
if (gcd(seq[i], seq[i + 1]) === 1)
return false;
}
return true;
}
// brute force: try all subsequences
function maxGoodSubseq(arr) {
let n = arr.length;
let maxLen = 0;
for (let mask = 1; mask < (1 << n); mask++) {
let subseq = [];
for (let i = 0; i < n; i++) {
if (mask & (1 << i))
subseq.push(arr[i]);
}
if (isGood(subseq))
maxLen = Math.max(maxLen, subseq.length);
}
return maxLen;
}
// Driver code
let arr = [2, 3, 6, 9, 10];
console.log(maxGoodSubseq(arr));
[Better Approach] DP Solution - O(n^2) Time and O(n) Space
The idea is to check all earlier elements for each index and extends the subsequence whenever gcd with the previous chosen element is greater than one. We maintain a dp array where dp[i] stores the longest good subsequence ending at index i. For each i, we scan all j < i and update dp[i] if gcd(arr[i], arr[j]) is not one. This approach is simple and easy to implement but becomes slow when n is large because every pair of indices is checked.
C++
#include <iostream>
#include <vector>
using namespace std;
// compute gcd
int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
// dp approach O(N^2)
int maxGoodSubseq(vector<int> &arr) {
int n = arr.size();
// dp[i] = longest valid subsequence ending at i
vector<int> dp(n, 1);
int ans = 1;
// check all j < i transitions
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
// update dp if arr[j] can precede arr[i]
if (gcd(arr[i], arr[j]) > 1)
dp[i] = max(dp[i], dp[j] + 1);
}
ans = max(ans, dp[i]);
}
return ans;
}
int main() {
vector<int> arr = {2, 3, 6, 9, 10};
cout << maxGoodSubseq(arr);
return 0;
}
Java
import java.util.ArrayList;
class GFG {
// compute gcd
static int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
// dp approach O(N^2)
static int maxGoodSubseq(int[] arr) {
int n = arr.length;
// dp[i] = longest valid subsequence ending at i
int[] dp = new int[n];
for (int i = 0; i < n; i++)
dp[i] = 1;
int ans = 1;
// check all j < i transitions
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
// update dp if arr[j] can precede arr[i]
if (gcd(arr[i], arr[j]) > 1)
dp[i] = Math.max(dp[i], dp[j] + 1);
}
ans = Math.max(ans, dp[i]);
}
return ans;
}
public static void main(String[] args) {
int[] arr = {2, 3, 6, 9, 10};
System.out.println(maxGoodSubseq(arr));
}
}
Python
# compute gcd
def gcd(a, b):
return a if b == 0 else gcd(b, a % b)
# dp approach O(N^2)
def maxGoodSubseq(arr):
n = len(arr)
# dp[i] = longest valid subsequence ending at i
dp = [1] * n
ans = 1
# check all j < i transitions
for i in range(n):
for j in range(i):
# update dp if arr[j] can precede arr[i]
if gcd(arr[i], arr[j]) > 1:
dp[i] = max(dp[i], dp[j] + 1)
ans = max(ans, dp[i])
return ans
if __name__ == "__main__":
arr = [2, 3, 6, 9, 10]
print(maxGoodSubseq(arr))
C#
using System;
class GFG {
// compute gcd
static int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
// dp approach O(N^2)
static int maxGoodSubseq(int[] arr) {
int n = arr.Length;
// dp[i] = longest valid subsequence ending at i
int[] dp = new int[n];
for (int i = 0; i < n; i++)
dp[i] = 1;
int ans = 1;
// check all j < i transitions
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
// update dp if arr[j] can precede arr[i]
if (gcd(arr[i], arr[j]) > 1)
dp[i] = Math.Max(dp[i], dp[j] + 1);
}
ans = Math.Max(ans, dp[i]);
}
return ans;
}
static void Main() {
int[] arr = {2, 3, 6, 9, 10};
Console.WriteLine(maxGoodSubseq(arr));
}
}
JavaScript
// compute gcd
function gcd(a, b) {
return b === 0 ? a : gcd(b, a % b);
}
// dp approach O(N^2)
function maxGoodSubseq(arr) {
let n = arr.length;
// dp[i] = longest valid subsequence ending at i
let dp = new Array(n).fill(1);
let ans = 1;
// check all j < i transitions
for (let i = 0; i < n; i++) {
for (let j = 0; j < i; j++) {
// update dp if arr[j] can precede arr[i]
if (gcd(arr[i], arr[j]) > 1)
dp[i] = Math.max(dp[i], dp[j] + 1);
}
ans = Math.max(ans, dp[i]);
}
return ans;
}
// Driver code
let arr = [2, 3, 6, 9, 10];
console.log(maxGoodSubseq(arr));
[Expected Approach] Sieve Algorithm + Prime DP - O(n log(max(arr))) Time and O(max(arr)) Space
The idea is to preprocess the smallest prime factor for every number up to the maximum array value. Using this SPF table, each number can be factorized in log time. For each distinct prime factor, we store the best subsequence length that ends with a number divisible by that prime. When processing a new number, we extend the maximum value among its prime factors and update these entries. This avoids checking pairs and gives a fast near linear solution.
C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// build SPF table
void buildSPF(vector<int> &spf, int maxV) {
for (int i = 2; i <= maxV; i++)
spf[i] = i;
for (int i = 2; i * i <= maxV; i++) {
if (spf[i] == i) {
for (int j = i * i; j <= maxV; j += i)
if (spf[j] == j)
spf[j] = i;
}
}
}
// factorize using SPF
vector<int> getPrimes(int x, vector<int> &spf) {
vector<int> primes;
while (x > 1) {
int p = spf[x];
primes.push_back(p);
while (x % p == 0)
x /= p;
}
return primes;
}
// expected approach
int maxGoodSubseq(vector<int> &arr) {
int n = arr.size();
int maxV = *max_element(arr.begin(), arr.end());
vector<int> spf(maxV + 1);
buildSPF(spf, maxV);
vector<int> best(maxV + 1, 0);
int ans = 1;
for (int x : arr) {
vector<int> primes = getPrimes(x, spf);
int cur = 1;
for (int p : primes)
cur = max(cur, best[p] + 1);
for (int p : primes)
best[p] = cur;
ans = max(ans, cur);
}
return ans;
}
int main() {
vector<int> arr = {2, 3, 6, 9, 10};
cout << maxGoodSubseq(arr);
return 0;
}
Java
import java.util.ArrayList;
class GFG {
// build SPF table
static void buildSPF(int[] spf, int maxV) {
for (int i = 2; i <= maxV; i++)
spf[i] = i;
for (int i = 2; i * i <= maxV; i++) {
if (spf[i] == i) {
for (int j = i * i; j <= maxV; j += i)
if (spf[j] == j)
spf[j] = i;
}
}
}
// factorize using SPF
static ArrayList<Integer> getPrimes(int x, int[] spf) {
ArrayList<Integer> primes = new ArrayList<>();
while (x > 1) {
int p = spf[x];
primes.add(p);
while (x % p == 0)
x /= p;
}
return primes;
}
// expected approach
static int maxGoodSubseq(int[] arr) {
int n = arr.length;
int maxV = 0;
for (int x : arr)
maxV = Math.max(maxV, x);
int[] spf = new int[maxV + 1];
buildSPF(spf, maxV);
int[] best = new int[maxV + 1];
int ans = 1;
for (int x : arr) {
ArrayList<Integer> primes = getPrimes(x, spf);
int cur = 1;
for (int p : primes)
cur = Math.max(cur, best[p] + 1);
for (int p : primes)
best[p] = cur;
ans = Math.max(ans, cur);
}
return ans;
}
public static void main(String[] args) {
int[] arr = {2, 3, 6, 9, 10};
System.out.println(maxGoodSubseq(arr));
}
}
Python
# build SPF table
def buildSpf(maxV):
spf = list(range(maxV + 1))
i = 2
while i * i <= maxV:
if spf[i] == i:
j = i * i
while j <= maxV:
if spf[j] == j:
spf[j] = i
j += i
i += 1
return spf
# factorize using SPF
def getPrimes(x, spf):
primes = []
while x > 1:
p = spf[x]
primes.append(p)
while x % p == 0:
x //= p
return primes
# expected approach
def maxGoodSubseq(arr):
n = len(arr)
maxV = max(arr)
spf = buildSpf(maxV)
best = [0] * (maxV + 1)
ans = 1
for x in arr:
primes = getPrimes(x, spf)
cur = 1
for p in primes:
cur = max(cur, best[p] + 1)
for p in primes:
best[p] = cur
ans = max(ans, cur)
return ans
if __name__ == "__main__":
arr = [2, 3, 6, 9, 10]
print(maxGoodSubseq(arr))
C#
using System;
using System.Collections.Generic;
class GFG {
// build SPF
static void buildSPF(int[] spf, int maxV) {
for (int i = 2; i <= maxV; i++)
spf[i] = i;
for (int i = 2; i * i <= maxV; i++) {
if (spf[i] == i) {
for (int j = i * i; j <= maxV; j += i)
if (spf[j] == j)
spf[j] = i;
}
}
}
// factorize using SPF
static List<int> getPrimes(int x, int[] spf) {
List<int> primes = new List<int>();
while (x > 1) {
int p = spf[x];
primes.Add(p);
while (x % p == 0)
x /= p;
}
return primes;
}
// expected approach
static int maxGoodSubseq(int[] arr) {
int n = arr.Length;
int maxV = 0;
foreach (int x in arr)
maxV = Math.Max(maxV, x);
int[] spf = new int[maxV + 1];
buildSPF(spf, maxV);
int[] best = new int[maxV + 1];
int ans = 1;
foreach (int x in arr) {
List<int> primes = getPrimes(x, spf);
int cur = 1;
foreach (int p in primes)
cur = Math.Max(cur, best[p] + 1);
foreach (int p in primes)
best[p] = cur;
ans = Math.Max(ans, cur);
}
return ans;
}
static void Main() {
int[] arr = {2, 3, 6, 9, 10};
Console.WriteLine(maxGoodSubseq(arr));
}
}
JavaScript
// build SPF
function buildSPF(maxV) {
let spf = Array.from({ length: maxV + 1 }, (_, i) => i);
for (let i = 2; i * i <= maxV; i++) {
if (spf[i] === i) {
for (let j = i * i; j <= maxV; j += i) {
if (spf[j] === j)
spf[j] = i;
}
}
}
return spf;
}
// factorize using SPF
function getPrimes(x, spf) {
let primes = [];
while (x > 1) {
let p = spf[x];
primes.push(p);
while (x % p === 0)
x /= p;
}
return primes;
}
// expected approach
function maxGoodSubseq(arr) {
let n = arr.length;
let maxV = Math.max(...arr);
let spf = buildSPF(maxV);
let best = new Array(maxV + 1).fill(0);
let ans = 1;
for (let x of arr) {
let primes = getPrimes(x, spf);
let cur = 1;
for (let p of primes)
cur = Math.max(cur, best[p] + 1);
for (let p of primes)
best[p] = cur;
ans = Math.max(ans, cur);
}
return ans;
}
// Driver code
let arr = [2, 3, 6, 9, 10];
console.log(maxGoodSubseq(arr));
Explore
DSA Fundamentals
Data Structures
Algorithms
Advanced
Interview Preparation
Practice Problem