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++

 // C++ implementation of the above approach #include #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 = lpd = 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 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);        preCompute();        cout << maxLengthSubsequence(arr, n);     return 0; }

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, lpd = 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

 // 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 = lpd = 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 pos = new HashMap ();         // 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.

C#

 // 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 = lpd = 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

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.

Be the First to upvote.

Please write to us at contribute@geeksforgeeks.org to report any issue with the above content.