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

filter_none

edit
close

play_arrow

link
brightness_4
code

# 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

chevron_right


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


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# implementation of the 
// above approach 
using System;
using System.Collections;
  
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]; 
    Hashtable pos = new Hashtable(); 
  
    // 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[Convert.ToInt32(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 = Math.Max(ans, dp[i]); 
    
  
    return ans; 
  
// Driver code 
public static void Main() 
    int []arr = { 13, 2, 8, 6, 3, 1, 9 }; 
    int n = arr.Length - 1; 
  
    preCompute(); 
    Console.WriteLine(maxLengthSubsequence(arr, n)); 
}
  
// This code is contributed by Ryuga

chevron_right


Output:

5


My Personal Notes arrow_drop_up

An enthusiastic Java and web developer with a little affinity for tea, cricket, English, etymology, and reading

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.