Open In App

Minimum splits required to convert a number into prime segments

Improve
Improve
Like Article
Like
Save
Share
Report

Given a number in the form of a string s, the task is to calculate and display minimum splits required such that the segments formed are Prime or print Not Possible otherwise.
Examples: 
 

Input: s = “2351” 
Output :
Explanation: Given number is already prime.
Input: s = “2352” 
Output:
Explanation: Resultant prime segments are 23,5,2
Input: s = “2375672” 
Output :
Explanation: Resultant prime segments are 2,37567,2
 

 

Approach: 
This problem is a variation of Matrix Chain Multiplication and can be solved using Dynamic programming.
Try all possible splits recursively and at each split, check whether the segments formed are prime or not. Consider a 2D array dp where dp[i][j] shows the minimum splits from index i to j and returns dp[0][n] where n is the length of the string.
Recurrence : 
 

dp[i][j] = min(1 + solve(i, k) + solve(k + 1, j)) where i <= k <= j

Actually, in the exact recurrence written above, the left and right segments both are non-prime, then 1 + INT_MAX + INT_MAX will be negative which leads to an incorrect answer. 
So, separate calculations for the left and right segments are required. If any segment is found to be non-prime, no need to proceed further. Return min(1+left+right) otherwise.
Base cases considered are : 
 

  • If the number is prime, return 0
  • If i==j and the number is prime, return 0
  • If i==j and the number is not prime, return INT_MAX

Below code is the implementation of above approach:
 

C++




#include <bits/stdc++.h>
using namespace std;
 
int dp[1000][1000] = { 0 };
 
// Checking for prime
bool isprime(long long num)
{
    if (num <= 1)
        return false;
    for (int i = 2; i * i <= num; i++) {
        if (num % i == 0) {
            return false;
        }
    }
    return true;
}
// Conversion of string to int
long long convert(string s, int i, int j)
{
    long long temp = 0;
    for (int k = i; k <= j; k++) {
        temp = temp * 10 + (s[k] - '0');
    }
    return temp;
}
// Function to get the minimum splits
int solve(string s, int i, int j)
{
    // Convert the segment to integer or long long
    long long num = convert(s, i, j);
    // Number is prime
    if (isprime(num)) {
        return 0;
    }
    // If a single digit is prime
    if (i == j && isprime(num))
        return 0;
 
    // If single digit is not prime
    if (i == j && isprime(num) == false)
        return INT_MAX;
 
    if (dp[i][j])
        return dp[i][j];
 
    int ans = INT_MAX;
    for (int k = i; k < j; k++) {
        // Recur for left segment
        int left = solve(s, i, k);
        if (left == INT_MAX) {
            continue;
        }
 
        // Recur for right segment
        int right = solve(s, k + 1, j);
        if (right == INT_MAX) {
            continue;
        }
        // Minimum from left and right segment
        ans = min(ans, 1 + left + right);
    }
    return dp[i][j] = ans;
}
int main()
{
 
    string s = "2352";
    int n = s.length();
 
    int cuts = solve(s, 0, n - 1);
    if (cuts != INT_MAX) {
        cout << cuts;
    }
    else {
        cout << "Not Possible";
    }
}


Java




import java.util.*;
 
class GFG
{
 
    static int dp[][] = new int[1000][1000];
 
    // Checking for prime
    static boolean isprime(long num){
        int i;
        if (num <= 1)
            return false;
        for (i = 2; i * i <= num; i++) {
            if (num % i == 0) {
                return false;
            }
        }
        return true;
    }
 
    // Conversion of string to int
    static long convert(String s, int i, int j)
    {
        long temp = 0;
        int k;
        for (k = i; k <= j; k++) {
            temp = temp * 10 + (s.charAt(k) - '0');
        }
        return temp;
    }
 
    // Function to get the minimum splits
    static int solve(String s, int i, int j)
    {
        int k;
 
        // Convert the segment to integer or long long
        long num = convert(s, i, j);
 
        // Number is prime
        if (isprime(num)) {
            return 0;
        }
 
        // If a single digit is prime
        if (i == j && isprime(num))
            return 0;
     
        // If single digit is not prime
        if (i == j && isprime(num) == false)
            return Integer.MAX_VALUE;
     
        if (dp[i][j] != 0)
            return dp[i][j];
     
        int ans = Integer.MAX_VALUE;
        for (k = i; k < j; k++) {
 
            // Recur for left segment
            int left = solve(s, i, k);
            if (left == Integer.MAX_VALUE) {
                continue;
            }
     
            // Recur for right segment
            int right = solve(s, k + 1, j);
            if (right == Integer.MAX_VALUE) {
                continue;
            }
 
            // Minimum from left and right segment
            ans = Math.min(ans, 1 + left + right);
        }
        return dp[i][j] = ans;
    }
     
    public static void main (String []args)
    {
     
        String s = "2352";
        int n = s.length();
     
        int cuts = solve(s, 0, n - 1);
        if (cuts != Integer.MAX_VALUE) {
            System.out.print(cuts);
        }
        else {
            System.out.print("Not Possible");
        }
    }
}
 
// This code is contributed by chitranayal


Python3




# Python3 Implementation of the above approach
import numpy as np;
import sys
 
dp = np.zeros((1000,1000)) ;
 
INT_MAX = sys.maxsize;
 
# Checking for prime
def isprime(num) :
 
    if (num <= 1) :
        return False;
    for i in range(2, int(num ** (1/2)) + 1) :
        if (num % i == 0) :
            return False;
    return True;
 
# Conversion of string to int
def convert(s, i, j) :
 
    temp = 0;
    for k in range(i, j + 1) :
        temp = temp * 10 + (ord(s[k]) - ord('0'));
 
    return temp;
 
# Function to get the minimum splits
def solve(s, i, j) :
 
    # Convert the segment to integer or long long
    num = convert(s, i, j);
    # Number is prime
    if (isprime(num)) :
        return 0;
 
    # If a single digit is prime
    if (i == j and isprime(num)) :
        return 0;
 
    # If single digit is not prime
    if (i == j and isprime(num) == False) :
        return INT_MAX;
 
    if (dp[i][j]) :
        return dp[i][j];
 
    ans = INT_MAX;
     
    for k in range(i, j) :
        # Recur for left segment
        left = solve(s, i, k);
        if (left == INT_MAX) :
            continue;
 
        # Recur for right segment
        right = solve(s, k + 1, j);
        if (right == INT_MAX) :
            continue;
     
        # Minimum from left and right segment
        ans = min(ans, 1 + left + right);
     
    dp[i][j] = ans;
     
    return ans;
 
# Driver code   
if __name__ == "__main__" :
 
    s = "2352";
    n = len(s);
 
    cuts = solve(s, 0, n - 1);
    if (cuts != INT_MAX) :
        print(cuts);
     
    else :
        print("Not Possible");
 
# This code is converted by Yash_R


C#




using System;
 
class GFG
{
  
    static int [,]dp = new int[1000,1000];
  
    // Checking for prime
    static bool isprime(long num){
        int i;
        if (num <= 1)
            return false;
        for (i = 2; i * i <= num; i++) {
            if (num % i == 0) {
                return false;
            }
        }
        return true;
    }
  
    // Conversion of string to int
    static long convert(String s, int i, int j)
    {
        long temp = 0;
        int k;
        for (k = i; k <= j; k++) {
            temp = temp * 10 + (s[k] - '0');
        }
        return temp;
    }
  
    // Function to get the minimum splits
    static int solve(String s, int i, int j)
    {
        int k;
  
        // Convert the segment to integer or long long
        long num = convert(s, i, j);
  
        // Number is prime
        if (isprime(num)) {
            return 0;
        }
  
        // If a single digit is prime
        if (i == j && isprime(num))
            return 0;
      
        // If single digit is not prime
        if (i == j && isprime(num) == false)
            return int.MaxValue;
      
        if (dp[i,j] != 0)
            return dp[i, j];
      
        int ans = int.MaxValue;
        for (k = i; k < j; k++) {
  
            // Recur for left segment
            int left = solve(s, i, k);
            if (left == int.MaxValue) {
                continue;
            }
      
            // Recur for right segment
            int right = solve(s, k + 1, j);
            if (right == int.MaxValue) {
                continue;
            }
  
            // Minimum from left and right segment
            ans = Math.Min(ans, 1 + left + right);
        }
        return dp[i,j] = ans;
    }
      
    public static void Main(String []args)
    {
      
        String s = "2352";
        int n = s.Length;
      
        int cuts = solve(s, 0, n - 1);
        if (cuts != int.MaxValue) {
            Console.Write(cuts);
        }
        else {
            Console.Write("Not Possible");
        }
    }
}
 
// This code is contributed by PrinciRaj1992


Javascript




<script>
 
let dp = new Array(1000);
 
for(let i = 0; i < 1000; i++){
    dp[i] = new Array(1000)
}
 
// Checking for prime
function isprime(num)
{
    if (num <= 1)
        return false;
    for (let i = 2; i * i <= num; i++) {
        if (num % i == 0) {
            return false;
        }
    }
    return true;
}
// Conversion of string to int
function convert(s, i, j)
{
    let temp = 0;
    for (let k = i; k <= j; k++) {
        temp = temp * 10 + (s[k] - '0');
    }
    return temp;
}
// Function to get the minimum splits
function solve(s, i, j)
{
    // Convert the segment to integer or long long
    let num = convert(s, i, j);
    // Number is prime
    if (isprime(num)) {
        return 0;
    }
    // If a single digit is prime
    if (i == j && isprime(num))
        return 0;
 
    // If single digit is not prime
    if (i == j && isprime(num) == false)
        return Number.MAX_SAFE_INTEGER;
 
    if (dp[i][j])
        return dp[i][j];
 
    let ans = Number.MAX_SAFE_INTEGER;
    for (let k = i; k < j; k++) {
        // Recur for left segment
        let left = solve(s, i, k);
        if (left == Number.MAX_SAFE_INTEGER) {
            continue;
        }
 
        // Recur for right segment
        let right = solve(s, k + 1, j);
        if (right == Number.MAX_SAFE_INTEGER) {
            continue;
        }
        // Minimum from left and right segment
        ans = Math.min(ans, 1 + left + right);
    }
    return dp[i][j] = ans;
}
 
 
 
    let s = "2352";
    let n = s.length;
 
    let cuts = solve(s, 0, n - 1);
    if (cuts != Number.MAX_SAFE_INTEGER) {
        document.write(cuts);
    }
    else {
        document.write("Not Possible");
    }
 
    // This code is contributed by _saurabh_jaiswal
 
</script>


Output

2

Time Complexity: O(n3/2)

Auxiliary Space: O(106)

Another approach : Using DP Tabulation method ( Iterative approach )

In this approach we create a 2D DP to compute and store subproblems this method is called DP tabulation because we find answer just by iterating the DP and calculate subproblems without the help of recursion.

Steps to solve this problem :

  • Define a 2D array dp of size n x n, where n is the length of the input string.
  • Calculate the ending index j as i + len – 1.
  • Convert the substring from index i to j to a long long integer and check if it is prime or not. Store the result in dp[i][j].
  • Iterate over all possible values of k such that i <= k < j.
  • Calculate the number of cuts required for the left substring from i to k, and the right substring from k+1 to j.
  • Add 1 to the sum of the cuts and store the minimum value in dp[i][j].
  • Return dp[0][n-1] if it is not INT_MAX, else return -1, indicating that it is not possible to split the string into prime numbers.

Implementation :

C++




#include <bits/stdc++.h>
using namespace std;
 
long long dp[1000][1000] = { 0 };
 
// Checking for prime
bool isprime(long long num)
{
    if (num <= 1)
        return false;
    for (long long i = 2; i * i <= num; i++) {
        if (num % i == 0) {
            return false;
        }
    }
    return true;
}
 
// Conversion of string to int
long long convert(string s, int i, int j)
{
    long long temp = 0;
    for (int k = i; k <= j; k++) {
        temp = temp * 10 + (s[k] - '0');
    }
    return temp;
}
 
// Function to get the minimum splits
long long solve(string s)
{
    int n = s.length();
    // base cases
    for (int i = 0; i < n; i++) {
        dp[i][i] = (isprime(s[i] - '0')) ? 0 : -1;
    }
    // fill dp table
    for (int len = 2; len <= n; len++) {
        for (int i = 0; i <= n - len; i++) {
            int j = i + len - 1;
            long long num = convert(s, i, j);
            dp[i][j] = (isprime(num)) ? 0 : -1;
            // check for all possible splits
            for (int k = i; k < j; k++) {
                long long left = dp[i][k];
                long long right = dp[k + 1][j];
                // if either side has no valid split, skip
                // this split
                if (left == -1 || right == -1) {
                    continue;
                }
                // update the minimum splits
                if (dp[i][j] == -1
                    || dp[i][j] > left + right + 1) {
                    dp[i][j] = left + right + 1;
                }
            }
        }
    }
    // return the minimum splits
    return dp[0][n - 1];
}
 
// Driver code
int main()
{
    string s = "2375672";
    long long cuts = solve(s);
    if (cuts != -1) {
        cout << cuts << endl;
    }
    else {
        cout << "Not Possible" << endl;
    }
    return 0;
}


Java




import java.util.*;
 
public class Main {
    static long[][] dp = new long[1000][1000];
 
    // Checking for prime
    static boolean isprime(long num)
    {
        if (num <= 1)
            return false;
        for (long i = 2; i * i <= num; i++) {
            if (num % i == 0) {
                return false;
            }
        }
        return true;
    }
 
    // Conversion of string to int
    static long convert(String s, int i, int j)
    {
        long temp = 0;
        for (int k = i; k <= j; k++) {
            temp = temp * 10 + (s.charAt(k) - '0');
        }
        return temp;
    }
 
    // Function to get the minimum splits
    static long solve(String s)
    {
        int n = s.length();
        // base cases
        for (int i = 0; i < n; i++) {
            dp[i][i]
                = (isprime(s.charAt(i) - '0')) ? 0 : -1;
        }
        // fill dp table
        for (int len = 2; len <= n; len++) {
            for (int i = 0; i <= n - len; i++) {
                int j = i + len - 1;
                long num = convert(s, i, j);
                dp[i][j] = (isprime(num)) ? 0 : -1;
                // check for all possible splits
                for (int k = i; k < j; k++) {
                    long left = dp[i][k];
                    long right = dp[k + 1][j];
                    // if either side has no valid split,
                    // skip this split
                    if (left == -1 || right == -1) {
                        continue;
                    }
                    // update the minimum splits
                    if (dp[i][j] == -1
                        || dp[i][j] > left + right + 1) {
                        dp[i][j] = left + right + 1;
                    }
                }
            }
        }
        // return the minimum splits
        return dp[0][n - 1];
    }
 
    // Driver code
    public static void main(String[] args)
    {
        String s = "2375672";
        long cuts = solve(s);
        if (cuts != -1) {
            System.out.println(cuts);
        }
        else {
            System.out.println("Not Possible");
        }
    }
}


Python3




# Python program for the above approach
import sys
 
# Checking for prime
def isprime(num):
    if num <= 1:
        return False
    for i in range(2, int(num**0.5)+1):
        if num % i == 0:
            return False
    return True
 
# Conversion of string to int
def convert(s, i, j):
    temp = 0
    for k in range(i, j+1):
        temp = temp * 10 + int(s[k])
    return temp
 
# Function to get the minimum splits
def solve(s):
    n = len(s)
    global dp
    dp = [[0 for j in range(n)] for i in range(n)]
    # base cases
    for i in range(n):
        dp[i][i] = 0 if isprime(int(s[i])) else -1
    # fill dp table
    for length in range(2, n+1):
        for i in range(n-length+1):
            j = i + length - 1
            num = convert(s, i, j)
            dp[i][j] = 0 if isprime(num) else -1
            # check for all possible splits
            for k in range(i, j):
                left = dp[i][k]
                right = dp[k+1][j]
                # if either side has no valid split,
                # skip this split
                if left == -1 or right == -1:
                    continue
                # update the minimum splits
                if dp[i][j] == -1 or dp[i][j] > left + right + 1:
                    dp[i][j] = left + right + 1
    # return the minimum splits
    return dp[0][n-1]
 
# Driver code
if __name__ == '__main__':
    s = "2375672"
    cuts = solve(s)
    if cuts != -1:
        print(cuts)
    else:
        print("Not Possible")


C#




using System;
 
public class Program
{
    static long[,] dp = new long[1000, 1000];
 
    // Checking for prime
    static bool IsPrime(long num)
    {
        if (num <= 1)
            return false;
        for (long i = 2; i * i <= num; i++)
        {
            if (num % i == 0)
            {
                return false;
            }
        }
        return true;
    }
 
    // Conversion of string to int
    static long Convert(string s, int i, int j)
    {
        long temp = 0;
        for (int k = i; k <= j; k++)
        {
            temp = temp * 10 + (s[k] - '0');
        }
        return temp;
    }
 
    // Function to get the minimum splits
    static long Solve(string s)
    {
        int n = s.Length;
        // base cases
        for (int i = 0; i < n; i++)
        {
            dp[i, i] = (IsPrime(s[i] - '0')) ? 0 : -1;
        }
        // fill dp table
        for (int len = 2; len <= n; len++)
        {
            for (int i = 0; i <= n - len; i++)
            {
                int j = i + len - 1;
                long num = Convert(s, i, j);
                dp[i, j] = (IsPrime(num)) ? 0 : -1;
                // check for all possible splits
                for (int k = i; k < j; k++)
                {
                    long left = dp[i, k];
                    long right = dp[k + 1, j];
                    // if either side has no valid split,
                    // skip this split
                    if (left == -1 || right == -1)
                    {
                        continue;
                    }
                    // update the minimum splits
                    if (dp[i, j] == -1 || dp[i, j] > left + right + 1)
                    {
                        dp[i, j] = left + right + 1;
                    }
                }
            }
        }
        // return the minimum splits
        return dp[0, n - 1];
    }
 
    // Driver code
    public static void Main(string[] args)
    {
        string s = "2375672";
        long cuts = Solve(s);
        if (cuts != -1)
        {
            Console.WriteLine(cuts);
        }
        else
        {
            Console.WriteLine("Not Possible");
        }
    }
}


Javascript




// JavaScript code to get the minimum splits
 
let dp = new Array(1000).fill(0).map(() => new Array(1000).fill(0));
 
// Checking for prime
function isprime(num) {
    if (num <= 1) {
        return false;
    }
    for (let i = 2; i * i <= num; i++) {
        if (num % i == 0) {
            return false;
        }
    }
    return true;
}
 
// Conversion of string to int
function convert(s, i, j) {
    let temp = 0;
    for (let k = i; k <= j; k++) {
        temp = temp * 10 + (s[k] - '0');
    }
    return temp;
}
 
// Function to get the minimum splits
function solve(s) {
    let n = s.length;
    // base cases
    for (let i = 0; i < n; i++) {
        dp[i][i] = (isprime(s[i] - '0')) ? 0 : -1;
    }
    // fill dp table
    for (let len = 2; len <= n; len++) {
        for (let i = 0; i <= n - len; i++) {
            let j = i + len - 1;
            let num = convert(s, i, j);
            dp[i][j] = (isprime(num)) ? 0 : -1;
            // check for all possible splits
            for (let k = i; k < j; k++) {
                let left = dp[i][k];
                let right = dp[k + 1][j];
                // if either side has no valid split, skip this split
                if (left == -1 || right == -1) {
                    continue;
                }
                // update the minimum splits
                if (dp[i][j] == -1 || dp[i][j] > left + right + 1) {
                    dp[i][j] = left + right + 1;
                }
            }
        }
    }
    // return the minimum splits
    return dp[0][n - 1];
}
 
// Driver code
let s = "2375672";
let cuts = solve(s);
if (cuts != -1) {
    console.log(cuts);
}
else {
    console.log("Not Possible");
}


Output:

2

Time Complexity: O(n^3)

Auxiliary Space: O(N^2)



Last Updated : 17 Oct, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads