Split the given string into Primes : Digit DP
Given a string str that represents a large number, the task is to find the minimum number of segments the given string can be divided such that each segment is a prime number in the range of 1 to 106.
Examples:
Input: str = “13499315”
Output: 3
Explanation:
The number can be segmented as [13499, 31, 5]
Input: str = “43”
Output: 1
Explanation:
The number can be segmented as [43]
Naive Approach: The idea is to consider every prefix up to 6 digits( Since it is given that the primes are less than 106) and check if it is a prime number or not. If the prefix is a prime number, then recursively call the function to check the remaining string. If a non-negative number is returned, then it is considered as a possible arrangement. If none of the possible combinations returns a positive number, then -1 is printed.
Below is the implementation of the above approach:
C++
#include <iostream>
#include <string>
using namespace std;
bool checkPrime(string number)
{
int num = stoi(number);
for ( int i = 2; i * i <= num; i++)
if ((num % i) == 0)
return false ;
return true ;
}
int splitIntoPrimes(string number)
{
if (number.length() == 0)
return 0;
if (number.length() <= 6 and checkPrime(number))
return 1;
else {
int numLen = number.length();
int ans = 1000000;
for ( int i = 1; i <= 6 && i <= numLen; i++) {
if (checkPrime(number.substr(0, i))) {
int val = splitIntoPrimes(number.substr(i));
if (val != -1) {
ans = min(ans, 1 + val);
}
}
}
if (ans == 1000000)
return -1;
return ans;
}
}
int main()
{
cout << splitIntoPrimes( "13499315" ) << "\n" ;
cout << splitIntoPrimes( "43" ) << "\n" ;
return 0;
}
|
Java
import java.util.*;
class GFG{
static boolean checkPrime(String number)
{
int num = Integer.valueOf(number);
for ( int i = 2 ; i * i <= num; i++)
if ((num % i) == 0 )
return false ;
return true ;
}
static int splitIntoPrimes(String number)
{
if (number.length() == 0 )
return 0 ;
if (number.length() <= 6 && checkPrime(number))
return 1 ;
else {
int numLen = number.length();
int ans = 1000000 ;
for ( int i = 1 ; i <= 6 && i <= numLen; i++) {
if (checkPrime(number.substring( 0 , i))) {
int val = splitIntoPrimes(number.substring(i));
if (val != - 1 ) {
ans = Math.min(ans, 1 + val);
}
}
}
if (ans == 1000000 )
return - 1 ;
return ans;
}
}
public static void main(String[] args)
{
System.out.print(splitIntoPrimes( "13499315" )+ "\n" );
System.out.print(splitIntoPrimes( "43" )+ "\n" );
}
}
|
Python3
def checkPrime(number) :
num = int (number)
for i in range ( 2 , int (num * * 0.5 )) :
if ((num % i) = = 0 ) :
return False
return True
def splitIntoPrimes(number) :
if ( number = = '' ) :
return 0
if ( len (number)< = 6 and checkPrime(number) ) :
return 1
else :
numLen = len (number)
ans = 1000000
for i in range ( 1 , ( min ( 6 , numLen ) + 1 ) ) :
if ( checkPrime( number[:i] ) ) :
val = splitIntoPrimes( number[i:] )
if (val ! = - 1 ) :
ans = min (ans, 1 + val)
if ( ans = = 1000000 ) :
return - 1
return ans
print (splitIntoPrimes( "13499315" ))
print (splitIntoPrimes( "43" ))
|
C#
using System;
class GFG{
static bool checkPrime(String number)
{
int num = Int32.Parse(number);
for ( int i = 2; i * i <= num; i++)
if ((num % i) == 0)
return false ;
return true ;
}
static int splitIntoPrimes(String number)
{
if (number.Length == 0)
return 0;
if (number.Length <= 6 && checkPrime(number))
return 1;
else {
int numLen = number.Length;
int ans = 1000000;
for ( int i = 1; i <= 6 && i <= numLen; i++) {
if (checkPrime(number.Substring(0, i))) {
int val = splitIntoPrimes(number.Substring(i));
if (val != -1) {
ans = Math.Min(ans, 1 + val);
}
}
}
if (ans == 1000000)
return -1;
return ans;
}
}
public static void Main(String[] args)
{
Console.Write(splitIntoPrimes( "13499315" )+ "\n" );
Console.Write(splitIntoPrimes( "43" )+ "\n" );
}
}
|
Javascript
<script>
function checkPrime(number)
{
let num = String(number);
for (let i = 2; i * i <= num; i++)
if ((num % i) == 0)
return false ;
return true ;
}
function splitIntoPrimes(number)
{
if (number.length == 0)
return 0;
if (number.length <= 6 && checkPrime(number))
return 1;
else {
let numLen = number.length;
let ans = 1000000;
for (let i = 1; i <= 6 && i <= numLen; i++) {
if (checkPrime(number.substr(0, i))) {
let val = splitIntoPrimes(number.substr(i));
if (val != -1) {
ans = Math.min(ans, 1 + val);
}
}
}
if (ans == 1000000)
return -1;
return ans;
}
}
document.write(splitIntoPrimes( "13499315" ) + "<br>" );
document.write(splitIntoPrimes( "43" ) + "<br>" );
</script>
|
Time Complexity:
- The time complexity for the above approach would be of O(N5/2) where N is the length of the input string.
- The complexity to find all the possible combinations recursively is O(N2).
- For every combination, to check if the number is a prime number or not, an additional O(N0.5) time is used.
- This makes the time complexity O(N5/2).
Dynamic Programming Approach: The given problem is seen to exhibit an overlapping subproblem property. Therefore, dynamic programming can be used to efficiently solve this question.
A splitDP[] array is defined and used where splitDP[i] denotes the minimum number of splits required in the prefix string of length ‘i’ to break it into the prime subdivision.
The splitDP[] array is filled in the following way:
- A for loop is used to iterate through all the indices of the given string.
- For every index ‘i’ from the above loop, another loop is iterated from 1 to 6 to check if the substring from (i + j)th index forms a prime or not.
- If it forms a prime number, then the value at splitDP[] is updated as:
splitDP[i + j] = min(splitDP[i + j], 1 + splitDP[i]);
- After updating all the values of the array, the value at the last index is the minimum number of splits for the entire string.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
bool checkPrime(string number)
{
int num = stoi(number);
for ( int i = 2; i * i <= num; i++)
if ((num % i) == 0)
return false ;
return true ;
}
int splitIntoPrimes(string number)
{
int numLen = number.length();
int splitDP[numLen + 1];
memset (splitDP, -1, sizeof (splitDP));
for ( int i = 1; i <= numLen; i++) {
if (i <= 6 && checkPrime(number.substr(0, i)))
splitDP[i] = 1;
if (splitDP[i] != -1) {
for ( int j = 1; j <= 6 && i + j <= numLen; j++) {
if (checkPrime(number.substr(i, j))) {
if (splitDP[i + j] == -1)
splitDP[i + j] = 1 + splitDP[i];
else
splitDP[i + j] = min(splitDP[i + j],
1 + splitDP[i]);
}
}
}
}
return splitDP[numLen];
}
int main()
{
cout << splitIntoPrimes( "13499315" ) << "\n" ;
cout << splitIntoPrimes( "43" ) << "\n" ;
return 0;
}
|
Java
import java.util.*;
class GFG{
static boolean checkPrime(String number)
{
if (number.length()== 0 )
return true ;
int num = Integer.parseInt(number);
for ( int i = 2 ; i * i <= num; i++)
if ((num % i) == 0 )
return false ;
return true ;
}
static int splitIntoPrimes(String number)
{
int numLen = number.length();
int []splitDP = new int [numLen + 1 ];
Arrays.fill(splitDP, - 1 );
for ( int i = 1 ; i <= numLen; i++) {
if (i <= 6 && checkPrime(number.substring( 0 , i)))
splitDP[i] = 1 ;
if (splitDP[i] != - 1 ) {
for ( int j = 1 ; j <= 6 && i + j <= numLen; j++) {
if (checkPrime(number.substring(i, i+j))) {
if (splitDP[i + j] == - 1 )
splitDP[i + j] = 1 + splitDP[i];
else
splitDP[i + j] = Math.min(splitDP[i + j],
1 + splitDP[i]);
}
}
}
}
return splitDP[numLen];
}
public static void main(String[] args)
{
System.out.print(splitIntoPrimes( "13499315" )+ "\n" );
System.out.print(splitIntoPrimes( "43" )+ "\n" );
}
}
|
Python3
from math import sqrt
def checkPrime(number):
if ( len (number) = = 0 ):
return True
num = int (number)
for i in range ( 2 , int (sqrt(num)) + 1 , 1 ):
if ((num % i) = = 0 ):
return False
return True
def splitIntoPrimes(number):
numLen = len (number)
splitDP = [ - 1 for i in range (numLen + 1 )]
for i in range ( 1 , numLen + 1 , 1 ):
if (i < = 6 and checkPrime(number[ 0 :i])):
splitDP[i] = 1
if (splitDP[i] ! = - 1 ):
j = 1
while (j < = 6 and i + j < = numLen):
if (checkPrime(number[i:i + j])):
if (splitDP[i + j] = = - 1 ):
splitDP[i + j] = 1 + splitDP[i]
else :
splitDP[i + j] = min (splitDP[i + j], 1 + splitDP[i])
j + = 1
return splitDP[numLen]
if __name__ = = '__main__' :
print (splitIntoPrimes( "13499315" ))
print (splitIntoPrimes( "43" ))
|
C#
using System;
class GFG{
static bool checkPrime(String number)
{
if (number.Length==0)
return true ;
int num = Int32.Parse(number);
for ( int i = 2; i * i <= num; i++)
if ((num % i) == 0)
return false ;
return true ;
}
static int splitIntoPrimes(String number)
{
int numLen = number.Length;
int []splitDP = new int [numLen + 1];
for ( int i = 0; i <= numLen; i++)
splitDP[i] = -1;
for ( int i = 1; i <= numLen; i++) {
if (i <= 6 && checkPrime(number.Substring(0, i)))
splitDP[i] = 1;
if (splitDP[i] != -1) {
for ( int j = 1; j <= 6 && i + j <= numLen; j++) {
if (checkPrime(number.Substring(i, j))) {
if (splitDP[i + j] == -1)
splitDP[i + j] = 1 + splitDP[i];
else
splitDP[i + j] = Math.Min(splitDP[i + j],
1 + splitDP[i]);
}
}
}
}
return splitDP[numLen];
}
public static void Main(String[] args)
{
Console.Write(splitIntoPrimes( "13499315" )+ "\n" );
Console.Write(splitIntoPrimes( "43" )+ "\n" );
}
}
|
Javascript
<script>
function checkPrime(number)
{
if (number.length == 0)
return true ;
let num = parseInt(number);
for (let i = 2; i * i <= num; i++)
if ((num % i) == 0)
return false ;
return true ;
}
function splitIntoPrimes(number)
{
let numLen = number.length;
let splitDP = new Array(numLen + 1);
for (let i = 0; i < splitDP.length; i++)
{
splitDP[i] = -1;
}
for (let i = 1; i <= numLen; i++)
{
if (i <= 6 && checkPrime(number.substring(0, i)))
splitDP[i] = 1;
if (splitDP[i] != -1)
{
for (let j = 1;
j <= 6 && i + j <= numLen;
j++)
{
if (checkPrime(number.substring(i, i + j)))
{
if (splitDP[i + j] == -1)
splitDP[i + j] = 1 + splitDP[i];
else
splitDP[i + j] = Math.min(
splitDP[i + j],
1 + splitDP[i]);
}
}
}
}
return splitDP[numLen];
}
document.write(splitIntoPrimes( "13499315" ) + "<br>" );
document.write(splitIntoPrimes( "43" ) + "<br>" );
</script>
|
Time Complexity:
- The time complexity of the above approach is O(N3/2) where N is the length of the input string.
- The time to iterate through all the indices is O(N).
- Since the inner for loop runs a constant number of times for every index, it’s run time can be considered as constant.
- For every index, the time taken to check whether the number is a prime or not is of O(N0.5).
- Therefore, the overall time complexity is O(N3/2).
Optimized Dynamic Programming Approach: The above approach can further be optimized by using the concept Sieve of Eratosthenes to precompute and store whether a number is prime or not and reducing the time complexity to check for a number at every iteration.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
void getPrimesFromSeive(set<string>& primes)
{
bool prime[1000001];
memset (prime, true , sizeof (prime));
prime[0] = prime[1] = false ;
for ( int i = 2; i * i <= 1000000; i++) {
if (prime[i] == true ) {
for ( int j = i * i; j <= 1000000; j += i)
prime[j] = false ;
}
}
for ( int i = 2; i <= 1000000; i++) {
if (prime[i] == true )
primes.insert(to_string(i));
}
}
int splitIntoPrimes(string number)
{
int numLen = number.length();
int splitDP[numLen + 1];
memset (splitDP, -1, sizeof (splitDP));
set<string> primes;
getPrimesFromSeive(primes);
for ( int i = 1; i <= numLen; i++) {
if (i <= 6 && (primes.find(number.substr(0, i))
!= primes.end()))
splitDP[i] = 1;
if (splitDP[i] != -1) {
for ( int j = 1; j <= 6 && i + j <= numLen; j++) {
if (primes.find(number.substr(i, j))
!= primes.end()) {
if (splitDP[i + j] == -1)
splitDP[i + j] = 1 + splitDP[i];
else
splitDP[i + j] = min(splitDP[i + j],
1 + splitDP[i]);
}
}
}
}
return splitDP[numLen];
}
int main()
{
cout << splitIntoPrimes( "13499315" ) << "\n" ;
cout << splitIntoPrimes( "43" ) << "\n" ;
return 0;
}
|
Java
import java.util.*;
class GFG{
static void getPrimesFromSeive(HashSet<String> primes)
{
boolean []prime = new boolean [ 1000001 ];
Arrays.fill(prime, true );
prime[ 0 ] = prime[ 1 ] = false ;
for ( int i = 2 ; i * i <= 1000000 ; i++) {
if (prime[i] == true ) {
for ( int j = i * i; j <= 1000000 ; j += i)
prime[j] = false ;
}
}
for ( int i = 2 ; i <= 1000000 ; i++) {
if (prime[i] == true )
primes.add(String.valueOf(i));
}
}
static int splitIntoPrimes(String number)
{
int numLen = number.length();
int []splitDP = new int [numLen + 1 ];
Arrays.fill(splitDP, - 1 );
HashSet<String> primes = new HashSet<String>();
getPrimesFromSeive(primes);
for ( int i = 1 ; i <= numLen; i++) {
if (i <= 6 && (primes.contains(number.substring( 0 , i))))
splitDP[i] = 1 ;
if (splitDP[i] != - 1 ) {
for ( int j = 1 ; j <= 6 && i + j <= numLen; j++) {
if (primes.contains(number.substring(i, i+j))) {
if (splitDP[i + j] == - 1 )
splitDP[i + j] = 1 + splitDP[i];
else
splitDP[i + j] = Math.min(splitDP[i + j],
1 + splitDP[i]);
}
}
}
}
return splitDP[numLen];
}
public static void main(String[] args)
{
System.out.print(splitIntoPrimes( "13499315" )+ "\n" );
System.out.print(splitIntoPrimes( "43" )+ "\n" );
}
}
|
Python3
def getPrimesFromSeive(primes):
prime = [ True ] * ( 1000001 )
prime[ 0 ], prime[ 1 ] = False , False
i = 2
while (i * i < = 1000000 ):
if (prime[i] = = True ):
for j in range (i * i, 1000001 , i):
prime[j] = False
i + = 1
for i in range ( 2 , 1000001 ):
if (prime[i] = = True ):
primes.append( str (i))
def splitIntoPrimes(number):
numLen = len (number)
splitDP = [ - 1 ] * (numLen + 1 )
primes = []
getPrimesFromSeive(primes)
for i in range ( 1 , numLen + 1 ):
if (i < = 6 and (number[ 0 : i] in primes)):
splitDP[i] = 1
if (splitDP[i] ! = - 1 ):
j = 1
while (j < = 6 and (i + j < = numLen)):
if (number[i : i + j] in primes):
if (splitDP[i + j] = = - 1 ):
splitDP[i + j] = 1 + splitDP[i]
else :
splitDP[i + j] = min (splitDP[i + j],
1 + splitDP[i])
j + = 1
return splitDP[numLen]
print (splitIntoPrimes( "13499315" ))
print (splitIntoPrimes( "43" ))
|
C#
using System;
using System.Collections.Generic;
class GFG{
static void getPrimesFromSeive(HashSet<String> primes)
{
bool []prime = new bool [1000001];
for ( int i = 0; i < 1000001; i++)
prime[i] = true ;
prime[0] = prime[1] = false ;
for ( int i = 2; i * i <= 1000000; i++)
{
if (prime[i] == true )
{
for ( int j = i * i; j <= 1000000; j += i)
prime[j] = false ;
}
}
for ( int i = 2; i <= 1000000; i++)
{
if (prime[i] == true )
primes.Add(String.Join( "" , i));
}
}
static int splitIntoPrimes(String number)
{
int numLen = number.Length;
int []splitDP = new int [numLen + 1];
for ( int i = 0; i < numLen + 1; i++)
splitDP[i] = -1;
HashSet<String> primes = new HashSet<String>();
getPrimesFromSeive(primes);
for ( int i = 1; i <= numLen; i++)
{
if (i <= 6 && (primes.Contains
(number.Substring(0, i))))
splitDP[i] = 1;
if (splitDP[i] != -1)
{
for ( int j = 1; j <= 6 && i + j <= numLen; j++)
{
if (primes.Contains(number.Substring(i, j)))
{
if (splitDP[i + j] == -1)
splitDP[i + j] = 1 + splitDP[i];
else
splitDP[i + j] = Math.Min(splitDP[i + j],
1 + splitDP[i]);
}
}
}
}
return splitDP[numLen];
}
public static void Main(String[] args)
{
Console.Write(splitIntoPrimes( "13499315" ) + "\n" );
Console.Write(splitIntoPrimes( "43" ) + "\n" );
}
}
|
Javascript
<script>
function getPrimesFromSeive(primes)
{
let prime = new Array(1000001);
for (let i=0;i<prime.length;i++)
{
prime[i]= true ;
}
prime[0] = prime[1] = false ;
for (let i = 2; i * i <= 1000000; i++) {
if (prime[i] == true ) {
for (let j = i * i; j <= 1000000; j += i)
prime[j] = false ;
}
}
for (let i = 2; i <= 1000000; i++) {
if (prime[i] == true )
primes.add((i).toString());
}
}
function splitIntoPrimes(number)
{
let numLen = number.length;
let splitDP = new Array(numLen + 1);
for (let i=0;i<splitDP.length;i++)
{
splitDP[i]=-1;
}
let primes = new Set();
getPrimesFromSeive(primes);
for (let i = 1; i <= numLen; i++) {
if (i <= 6 && (primes.has(number.substring(0, i))))
splitDP[i] = 1;
if (splitDP[i] != -1) {
for (let j = 1; j <= 6 && i + j <= numLen; j++) {
if (primes.has(number.substring(i, i+j))) {
if (splitDP[i + j] == -1)
splitDP[i + j] = 1 + splitDP[i];
else
splitDP[i + j] = Math.min(splitDP[i + j],
1 + splitDP[i]);
}
}
}
}
return splitDP[numLen];
}
document.write(splitIntoPrimes( "13499315" )+ "<br>" );
document.write(splitIntoPrimes( "43" )+ "<br>" );
</script>
|
Time Complexity:
- This is the most efficient method as this runs in O(N) time complexity where N is the length of the input string.
- Since the sieve of Eratosthenes has a run time of O(N*log(log(N))) and the list of primes up to 106, the precomputation complexity can be calculated. However, since this is performed only once for any number of strings, it is not counted in calculating time complexity.
Last Updated :
02 Jun, 2021
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...