Given an array arr[], find the length of the longest subsequence such that for all pairs (i, j) where i != j, either arr[i] divides arr[j] or arr[j] divides arr[i]. If no such subsequence exists, return -1.
Examples:
Input: arr[] = [5, 3, 1, 4, 7]
Output: 2
Explanation: A valid longest subsequence is [1, 5] (or [1, 3], [1, 4]). No subsequence of length 3 satisfies this condition.
Input: arr[] = [2, 4, 6, 1, 3, 11]
Output: 3
Explanation: One valid longest subsequence is [2, 4, 1]. Hence, the maximum possible length is 3.
Table of Content
[Naive Approach] Generate All Subsequences and Validate Each - O((2 ^ n) * (n ^ 2)) Time and O(n) Space
The idea is to generate every possible subsequence of the given array using recursion. For each subsequence, check whether every pair of elements satisfies the condition that one element divides the other.
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
// Function to check whether the current
// subsequence is pairwise divisible.
bool isValidSubsequence(vector<int> &subseq)
{
int n = subseq.size();
for (int i = 0; i < n; i++)
{
for (int j = i + 1; j < n; j++)
{
// If neither element divides the other,
// then the subsequence is invalid.
if (subseq[i] % subseq[j] != 0 && subseq[j] % subseq[i] != 0)
return false;
}
}
return true;
}
// Function to generate all possible subsequences.
void generateSubsequences(int idx, vector<int> &arr, vector<int> &subseq, int &res)
{
// If all elements have been processed.
if (idx == arr.size())
{
// Update the answer if the current
// subsequence is valid.
if (subseq.size() > 1 && isValidSubsequence(subseq))
{
res = max(res, (int)subseq.size());
}
return;
}
// Include the current element.
subseq.push_back(arr[idx]);
generateSubsequences(idx + 1, arr, subseq, res);
// Exclude the current element.
subseq.pop_back();
generateSubsequences(idx + 1, arr, subseq, res);
}
// Function to find the length of the
// longest pairwise divisible subsequence.
int longestSubseq(vector<int> &arr)
{
vector<int> subseq;
int res = 0;
generateSubsequences(0, arr, subseq, res);
// If the maximum length is 0, it means
// no valid subsequence exists.
return (res == 0) ? -1 : res;
}
int main()
{
vector<int> arr = {2, 4, 6, 1, 3, 11};
cout << longestSubseq(arr);
return 0;
}
import java.util.*;
class GFG {
// Function to check whether the current
// subsequence is pairwise divisible.
static boolean
isValidSubsequence(ArrayList<Integer> subseq)
{
int n = subseq.size();
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
// If neither element divides the other,
// then the subsequence is invalid.
if (subseq.get(i) % subseq.get(j) != 0
&& subseq.get(j) % subseq.get(i) != 0)
return false;
}
}
return true;
}
// Function to generate all possible subsequences.
static void
generateSubsequences(int idx, int[] arr,
ArrayList<Integer> subseq,
int[] res)
{
// If all elements have been processed.
if (idx == arr.length) {
// Update the answer if the current
// subsequence is valid.
if (subseq.size() > 1
&& isValidSubsequence(subseq)) {
res[0] = Math.max(res[0], subseq.size());
}
return;
}
// Include the current element.
subseq.add(arr[idx]);
generateSubsequences(idx + 1, arr, subseq, res);
// Exclude the current element.
subseq.remove(subseq.size() - 1);
generateSubsequences(idx + 1, arr, subseq, res);
}
// Function to find the length of the
// longest pairwise divisible subsequence.
static int longestSubseq(int[] arr)
{
ArrayList<Integer> subseq = new ArrayList<>();
int[] res = { 0 };
generateSubsequences(0, arr, subseq, res);
// If the maximum length is 0, it means
// no valid subsequence exists.
return (res[0] == 0) ? -1 : res[0];
}
public static void main(String[] args)
{
int[] arr = { 2, 4, 6, 1, 3, 11 };
System.out.println(longestSubseq(arr));
}
}
from typing import List
# Function to check whether the current
# subsequence is pairwise divisible.
def isValidSubsequence(subseq: List[int]) -> bool:
n = len(subseq)
for i in range(n):
for j in range(i + 1, n):
# If neither element divides the other,
# then the subsequence is invalid.
if subseq[i] % subseq[j] != 0 and subseq[j] % subseq[i] != 0:
return False
return True
# Function to generate all possible subsequences.
def generateSubsequences(idx: int, arr: List[int], subseq: List[int], res: List[int]) -> None:
# If all elements have been processed.
if idx == len(arr):
# Update the answer if the current
# subsequence is valid.
if len(subseq) > 1 and isValidSubsequence(subseq):
res[0] = max(res[0], len(subseq))
return
# Include the current element.
subseq.append(arr[idx])
generateSubsequences(idx + 1, arr, subseq, res)
# Exclude the current element.
subseq.pop()
generateSubsequences(idx + 1, arr, subseq, res)
# Function to find the length of the
# longest pairwise divisible subsequence.
def longestSubseq(arr: List[int]) -> int:
subseq = []
res = [0]
generateSubsequences(0, arr, subseq, res)
# If the maximum length is 0, it means
# no valid subsequence exists.
return -1 if res[0] == 0 else res[0]
if __name__ == "__main__":
arr = [2, 4, 6, 1, 3, 11]
print(longestSubseq(arr))
using System;
using System.Collections.Generic;
class GFG {
// Function to check whether the current
// subsequence is pairwise divisible.
static bool IsValidSubsequence(List<int> subseq)
{
int n = subseq.Count;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
// If neither element divides the other,
// then the subsequence is invalid.
if (subseq[i] % subseq[j] != 0
&& subseq[j] % subseq[i] != 0)
return false;
}
}
return true;
}
// Function to generate all possible subsequences.
static void GenerateSubsequences(int idx, int[] arr,
List<int> subseq,
ref int res)
{
// If all elements have been processed.
if (idx == arr.Length) {
// Update the answer if the current
// subsequence is valid.
if (subseq.Count > 1
&& IsValidSubsequence(subseq)) {
res = Math.Max(res, subseq.Count);
}
return;
}
// Include the current element.
subseq.Add(arr[idx]);
GenerateSubsequences(idx + 1, arr, subseq, ref res);
// Exclude the current element.
subseq.RemoveAt(subseq.Count - 1);
GenerateSubsequences(idx + 1, arr, subseq, ref res);
}
// Function to find the length of the
// longest pairwise divisible subsequence.
static int longestSubseq(int[] arr)
{
List<int> subseq = new List<int>();
int res = 0;
GenerateSubsequences(0, arr, subseq, ref res);
// If the maximum length is 0, it means
// no valid subsequence exists.
return (res == 0) ? -1 : res;
}
static void Main(string[] args)
{
int[] arr = { 2, 4, 6, 1, 3, 11 };
Console.WriteLine(longestSubseq(arr));
}
}
// Function to check whether the current
// subsequence is pairwise divisible.
function isValidSubsequence(subseq)
{
const n = subseq.length;
for (let i = 0; i < n; i++) {
for (let j = i + 1; j < n; j++) {
// If neither element divides the other,
// then the subsequence is invalid.
if (subseq[i] % subseq[j] !== 0
&& subseq[j] % subseq[i] !== 0) {
return false;
}
}
}
return true;
}
// Function to generate all possible subsequences.
function generateSubsequences(idx, arr, subseq, res)
{
// If all elements have been processed.
if (idx === arr.length) {
// Update the answer if the current
// subsequence is valid.
if (subseq.length > 1
&& isValidSubsequence(subseq)) {
res.maxLen
= Math.max(res.maxLen, subseq.length);
}
return;
}
// Include the current element.
subseq.push(arr[idx]);
generateSubsequences(idx + 1, arr, subseq, res);
// Exclude the current element.
subseq.pop();
generateSubsequences(idx + 1, arr, subseq, res);
}
// Function to find the length of the
// longest pairwise divisible subsequence.
function longestSubseq(arr)
{
const subseq = [];
const res = {maxLen : 0};
generateSubsequences(0, arr, subseq, res);
// If the maximum length is 0, it means
// no valid subsequence exists.
return res.maxLen === 0 ? -1 : res.maxLen;
}
// Driver Code
const arr = [ 2, 4, 6, 1, 3, 11 ];
console.log(longestSubseq(arr));
Output
3
[Expected Approach] Using Dynamic Programming after Sorting - O(n ^ 2) Time and O(n) Space
This problem is a variation of Longest Increasing Sequence.
The idea is to first sort the array so that every divisor appears before its multiples. Then, use dynamic programming where dp[i] stores the length of the longest valid subsequence ending at arr[i]. For every previous element, if it divides the current element, extend the subsequence. The maximum value in the dp array is the required answer.
Working of Approach:
- Sort the array in ascending order so that every divisor appears before its possible multiples.
- Create a DP array where dp[i] stores the length of the longest valid pairwise divisible subsequence ending at index i.
- For each element, check all previous elements. If the current element is divisible by a previous element, update dp[i] by extending the subsequence ending at that previous element.
- Keep track of the maximum value in the DP array while processing all elements.
- If the maximum subsequence length is greater than 1, return it; otherwise, return -1.
Let us understand with an example:
Input: arr[] = [2, 4, 6, 1, 3, 11]
- After sorting, the array becomes arr[] = [1, 2, 3, 4, 6, 11]. Initialize dp = [1, 1, 1, 1, 1, 1].
- For 2, update dp[1] = 2. For 3, update dp[2] = 2. For 4, since it is divisible by both 1 and 2, update dp[3] = 3.
- For 6, since it is divisible by 1, 2, and 3, update dp[4] = 3. For 11, only 1 divides it, so dp[5] = 2.
- The final dp array becomes [1, 2, 2, 3, 3, 2], where dp[3] = 3 represents the subsequence [1, 2, 4] and dp[4] = 3 represents [1, 3, 6].
- Hence, the maximum value in the dp array is 3, so the length of the longest pairwise divisible subsequence is 3.
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
int longestSubseq(vector<int> &arr)
{
int n = arr.size();
// Sorting the array in ascending order.
sort(arr.begin(), arr.end());
// dp array to store the length of the
// longest subsequence ending at each index.
vector<int> dp(n, 1);
// Iterating through the array to
// find the longest subsequence.
for (int j = 1; j < n; j++)
{
for (int i = 0; i < j; i++)
{
// Checking if the current number
// is divisible by the number at the
// previous index.
if (arr[j] % arr[i] == 0)
{
// Updating the length of subsequence
// if a longer one is found.
dp[j] = max(dp[j], dp[i] + 1);
}
}
}
// Finding the maximum length of the subsequence.
int maxLength = *max_element(dp.begin(), dp.end());
// If the maximum length is 1, it means no subsequence exists, so returning -1.
return maxLength == 1 ? -1 : maxLength;
}
int main()
{
vector<int> arr = {2, 4, 6, 1, 3, 11};
cout << longestSubseq(arr);
return 0;
}
import java.util.*;
class GFG {
static int longestSubseq(int[] arr)
{
int n = arr.length;
// Sorting the array in ascending order.
Arrays.sort(arr);
// dp array to store the length of the
// longest subsequence ending at each index.
int[] dp = new int[n];
Arrays.fill(dp, 1);
// Iterating through the array to
// find the longest subsequence.
for (int j = 1; j < n; j++) {
for (int i = 0; i < j; i++) {
// Checking if the current number
// is divisible by the number at the
// previous index.
if (arr[j] % arr[i] == 0) {
// Updating the length of subsequence
// if a longer one is found.
dp[j] = Math.max(dp[j], dp[i] + 1);
}
}
}
// Finding the maximum length of the subsequence.
int maxLength = 1;
for (int x : dp)
maxLength = Math.max(maxLength, x);
// If the maximum length is 1, it means no
// subsequence exists, so returning -1.
return maxLength == 1 ? -1 : maxLength;
}
public static void main(String[] args)
{
int[] arr = { 2, 4, 6, 1, 3, 11 };
System.out.println(longestSubseq(arr));
}
}
from typing import List
def longestSubseq(arr: List[int]) -> int:
n = len(arr)
# Sorting the array in ascending order.
arr.sort()
# dp array to store the length of the
# longest subsequence ending at each index.
dp = [1] * n
# Iterating through the array to
# find the longest subsequence.
for j in range(1, n):
for i in range(j):
# Checking if the current number
# is divisible by the number at the
# previous index.
if arr[j] % arr[i] == 0:
# Updating the length of subsequence
# if a longer one is found.
dp[j] = max(dp[j], dp[i] + 1)
# Finding the maximum length of the subsequence.
maxLength = max(dp)
# If the maximum length is 1, it means no subsequence exists, so returning -1.
return -1 if maxLength == 1 else maxLength
if __name__ == "__main__":
arr = [2, 4, 6, 1, 3, 11]
print(longestSubseq(arr))
using System;
class GFG {
static int longestSubseq(int[] arr)
{
int n = arr.Length;
// Sorting the array in ascending order.
Array.Sort(arr);
// dp array to store the length of the
// longest subsequence ending at each index.
int[] dp = new int[n];
Array.Fill(dp, 1);
// Iterating through the array to
// find the longest subsequence.
for (int j = 1; j < n; j++) {
for (int i = 0; i < j; i++) {
// Checking if the current number
// is divisible by the number at the
// previous index.
if (arr[j] % arr[i] == 0) {
// Updating the length of subsequence
// if a longer one is found.
dp[j] = Math.Max(dp[j], dp[i] + 1);
}
}
}
// Finding the maximum length of the subsequence.
int maxLength = 1;
foreach(int x in dp) maxLength
= Math.Max(maxLength, x);
// If the maximum length is 1, it means no
// subsequence exists, so returning -1.
return maxLength == 1 ? -1 : maxLength;
}
static void Main(string[] args)
{
int[] arr = { 2, 4, 6, 1, 3, 11 };
Console.WriteLine(longestSubseq(arr));
}
}
function longestSubseq(arr)
{
let n = arr.length;
// Sorting the array in ascending order.
arr.sort((a, b) => a - b);
// dp array to store the length of the
// longest subsequence ending at each index.
let dp = new Array(n).fill(1);
// Iterating through the array to
// find the longest subsequence.
for (let j = 1; j < n; j++) {
for (let i = 0; i < j; i++) {
// Checking if the current number
// is divisible by the number at the
// previous index.
if (arr[j] % arr[i] === 0) {
// Updating the length of subsequence
// if a longer one is found.
dp[j] = Math.max(dp[j], dp[i] + 1);
}
}
}
// Finding the maximum length of the subsequence.
let maxLength = Math.max(...dp);
// If the maximum length is 1, it means no subsequence
// exists, so returning -1.
return maxLength === 1 ? -1 : maxLength;
}
// Driver Code
let arr = [ 2, 4, 6, 1, 3, 11 ];
console.log(longestSubseq(arr));
Output
3