Maximum length subsequence such that adjacent elements in the subsequence have a common factor

Given an array arr[], the task is to find the maximum length of a subsequence such that the adjacent elements in the subsequence have a common factor.

Examples:

Input: arr[] = { 13, 2, 8, 6, 3, 1, 9 }
Output: 5

Max length subsequence with satisfied conditions: { 2, 8, 6, 3, 9 }

Input: arr[] = { 1, 2, 2, 3, 3, 1 }
Output: 2

Approach: A naive approach is to consider all subsequences and check every subsequence whether it satisfies the condition.

An efficient solution is to use Dynamic programming. Let dp[i] denote the maximum length of subsequence including arr[i]. Then, the following relation holds for every prime p such that p is a prime factor of arr[i]:

dp[i] = max(dp[i], 1 + dp[pos[p]]) 
where pos[p] gives the index of p in the array 
where it last occurred.

Explanation: Traverse the array. For an element arr[i], there are 2 possibilities.

  1. If the prime factors of arr[i] have shown their first appearance in the array, then dp[i] = 1
  2. If the prime factors of arr[i] have already occurred, then this element can be added in the subsequence since there’s a common factor. Hence dp[i] = max(dp[i], 1 + dp[pos[p]]) where p is the common prime factor and pos[p] is the latest index of p in the array.

Below is the implementation of the above approach:

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ implementation of the above approach
#include <bits/stdc++.h>
#define N 100005
#define MAX 10000002
  
using namespace std;
  
int lpd[MAX];
  
// to compute least prime divisor of i
void preCompute()
{
    memset(lpd, 0, sizeof(lpd));
    lpd[0] = lpd[1] = 1;
    for (int i = 2; i * i < MAX; i++) {
        for (int j = i * 2; j < MAX; j += i) {
            if (lpd[j] == 0) {
                lpd[j] = i;
            }
        }
    }
    for (int i = 2; i < MAX; i++) {
        if (lpd[i] == 0) {
            lpd[i] = i;
        }
    }
}
  
// Function that returns the maximum
// length subsequence such that
// adjacent elements have a common factor.
int maxLengthSubsequence(int arr[], int n)
{
    int dp[N];
    unordered_map<int, int> pos;
  
    // Initialize dp array with 1.
    for (int i = 1; i <= n; i++)
        dp[i] = 1;
  
    for (int i = 1; i <= n; i++) {
        while (arr[i] > 1) {
            int p = lpd[arr[i]];
            if (pos[p]) {
                // p has appeared at least once.
                dp[i] = max(dp[i], 1 + dp[pos[p]]);
            }
            // Update latest occurence of prime p.
            pos[p] = i;
            while (arr[i] % p == 0)
                arr[i] /= p;
        }
    }
  
    // Take maximum value as the answer.
    int ans = 1;
    for (int i = 1; i <= n; i++) {
        ans = max(ans, dp[i]);
    }
  
    return ans;
}
  
// Driver code
int main()
{
    int arr[] = { 13, 2, 8, 6, 3, 1, 9 };
    int n = sizeof(arr) / sizeof(arr[0]);
  
    preCompute();
  
    cout << maxLengthSubsequence(arr, n);
    return 0;
}

chevron_right


Python3

# Python3 implementation of the
# above approach
import math as mt

N = 100005
MAX = 1000002

lpd = [0 for i in range(MAX)]

# to compute least prime divisor of i
def preCompute():

lpd[0], lpd[1] = 1, 1

for i in range(2, mt.ceil(mt.sqrt(MAX))):
for j in range(2 * i, MAX, i):
if (lpd[j] == 0):
lpd[j] = i

for i in range(2, MAX):
if (lpd[i] == 0):
lpd[i] = i

# Function that returns the maximum
# length subsequence such that
# adjacent elements have a common factor.
def maxLengthSubsequence(arr, n):
dp = [1 for i in range(N + 1)]

pos = dict()

# Initialize dp array with 1.
for i in range(1, n):
while (arr[i] > 1):
p = lpd[arr[i]]
if (p in pos.keys()):

# p has appeared at least once.
dp[i] = max(dp[i], 1 + dp[pos[p]])

# Update latest occurence of prime p.
pos[p] = i
while (arr[i] % p == 0):
arr[i] //= p

# Take maximum value as the answer.
ans = 1
for i in range(1, n + 1):
ans = max(ans, dp[i])

return ans

# Driver code
arr = [13, 2, 8, 6, 3, 1, 9]
n = len(arr)

preCompute()

print(maxLengthSubsequence(arr, n))

# This code is contributed by Mohit Kumar

Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java implementation of the above approach 
import java.util.*;
class GfG 
      
static int N = 100005 ;
static int MAX = 10000002
  
  
  
static int lpd[] = new int[MAX]; 
  
// to compute least prime divisor of i 
static void preCompute() 
    lpd[0] = lpd[1] = 1
    for (int i = 2; i * i < MAX; i++) 
    
        for (int j = i * 2; j < MAX; j += i) 
        
            if (lpd[j] == 0
            
                lpd[j] = i; 
            
        
    
    for (int i = 2; i < MAX; i++)
    
        if (lpd[i] == 0
        
            lpd[i] = i; 
        
    
  
// Function that returns the maximum 
// length subsequence such that 
// adjacent elements have a common factor. 
static int maxLengthSubsequence(int arr[], int n) 
    int dp[] = new int[N]; 
Map<Integer, Integer> pos = new HashMap<Integer, Integer> (); 
  
    // Initialize dp array with 1. 
    for (int i = 1; i <= n; i++) 
        dp[i] = 1
  
    for (int i = 1; i <= n; i++) 
    
        while (arr[i] > 1
        
            int p = lpd[arr[i]]; 
            if (pos.containsKey(p))
            
                // p has appeared at least once. 
                dp[i] = Math.max(dp[i], 1 + dp[pos.get(p)]); 
            
              
            // Update latest occurence of prime p. 
            pos.put(p, i); 
            while (arr[i] % p == 0
                arr[i] /= p; 
        
    
  
    // Take maximum value as the answer. 
    int ans = 1
    for (int i = 1; i <= n; i++)
    
        ans = Math.max(ans, dp[i]); 
    
  
    return ans; 
  
// Driver code 
public static void main(String[] args) 
    int arr[] = { 13, 2, 8, 6, 3, 1, 9 }; 
    int n = arr.length - 1
  
    preCompute(); 
    System.out.println(maxLengthSubsequence(arr, n)); 
}
  
// This code is contributed by Prerna Saini.

chevron_right


Output:

5


My Personal Notes arrow_drop_up