Given a string str, a partitioning of the string is a palindrome partitioning if every sub-string of the partition is a palindrome, the task is to find the minimum number of cuts needed for palindrome partitioning of the given string.

Palindrome Partition
Examples :
Input: str = “geek”
Output: 2
Explanation: We need to make minimum 2 cuts, i.e., “g ee k”
Input: str = “aaaa”
Output: 0
Explanation: The string is already a palindrome.
Input: str = “abcde”
Output: 4
Input: str = “abbac”
Output: 1
Recursive Approach for Palindrome Partitioning:
This is the naive approach to solving the Palindrome Partitioning problem. In this approach, we will try to apply all possible partitions and at the end return the correct combination of partitions.
This approach is similar to that of Matrix Chain Multiplication problem.
In this approach, we recursively evaluate the following conditions:
- If the current string is a palindrome, then we simply return true, as Palindrome Partitioning is possible.
- Else, like the Matrix Chain Multiplication problem,
- we try making cuts at all possible places,
- recursively calculate the cost for each cut
- return the minimum value.
Below is the implementation of the above approach.
C++
#include <bits/stdc++.h>
using namespace std;
bool isPalindrome(string String, int i, int j)
{
while (i < j) {
if (String[i] != String[j])
return false ;
i++;
j--;
}
return true ;
}
int minPalPartion(string String, int i, int j)
{
if (i >= j || isPalindrome(String, i, j))
return 0;
int ans = INT_MAX, count;
for ( int k = i; k < j; k++) {
count = minPalPartion(String, i, k)
+ minPalPartion(String, k + 1, j) + 1;
ans = min(ans, count);
}
return ans;
}
int main()
{
string str = "ababbbabbababa" ;
cout
<< "Min cuts needed for Palindrome Partitioning is "
<< minPalPartion(str, 0, str.length() - 1) << endl;
return 0;
}
|
Java
public class PalindromePartitioning {
static boolean isPalindrome(String str, int i, int j)
{
while (i < j) {
if (str.charAt(i) != str.charAt(j))
return false ;
i++;
j--;
}
return true ;
}
static int minPalPartition(String str, int i, int j)
{
if (i >= j || isPalindrome(str, i, j))
return 0 ;
int minCuts = Integer.MAX_VALUE;
for ( int k = i; k < j; k++) {
int cuts = minPalPartition(str, i, k)
+ minPalPartition(str, k + 1 , j) + 1 ;
minCuts = Math.min(minCuts, cuts);
}
return minCuts;
}
public static void main(String[] args)
{
String str = "ababbbabbababa" ;
System.out.println(
"Min cuts needed for Palindrome Partitioning is "
+ minPalPartition(str, 0 , str.length() - 1 ));
}
}
|
Python3
def is_palindrome(string, i, j):
while i < j:
if string[i] ! = string[j]:
return False
i + = 1
j - = 1
return True
def min_pal_partition(string, i, j):
if i > = j or is_palindrome(string, i, j):
return 0
ans = float ( 'inf' )
for k in range (i, j):
count = min_pal_partition(string, i, k) + \
min_pal_partition(string, k + 1 , j) + 1
ans = min (ans, count)
return ans
if __name__ = = "__main__" :
str = "ababbbabbababa"
print ( "Min cuts needed for Palindrome Partitioning is" ,
min_pal_partition( str , 0 , len ( str ) - 1 ))
|
C#
using System;
public class PalindromePartitioning {
static bool IsPalindrome( string str, int i, int j)
{
while (i < j) {
if (str[i] != str[j])
return false ;
i++;
j--;
}
return true ;
}
static int MinPalPartition( string str, int i, int j)
{
if (i >= j || IsPalindrome(str, i, j))
return 0;
int minCuts = int .MaxValue;
for ( int k = i; k < j; k++) {
int cuts = MinPalPartition(str, i, k)
+ MinPalPartition(str, k + 1, j) + 1;
minCuts = Math.Min(minCuts, cuts);
}
return minCuts;
}
public static void Main( string [] args)
{
string str = "ababbbabbababa" ;
Console.WriteLine(
"Min cuts needed for Palindrome Partitioning is "
+ MinPalPartition(str, 0, str.Length - 1));
}
}
|
Javascript
<script>
function isPalindrome(String, i, j)
{
while (i < j)
{
if (String[i] != String[j])
return false ;
i++;
j--;
}
return true ;
}
function minPalPartion(String, i, j)
{
if (i >= j || isPalindrome(String, i, j))
return 0;
let ans = Number.MAX_VALUE, count;
for (let k = i; k < j; k++)
{
count = minPalPartion(String, i, k) +
minPalPartion(String, k + 1, j) + 1;
ans = Math.min(ans, count);
}
return ans;
}
let str = "ababbbabbababa" ;
document.write( "Min cuts needed for " +
"Palindrome Partitioning is " +
minPalPartion(str, 0, str.length - 1));
</script>
|
Output
Min cuts needed for Palindrome Partitioning is 3
Time Complexity: O(2n)
Auxiliary Space: O(n)
Optimising Overlapping Sub-problems in Recursive Approach for Palindrome Partitioning in (O(n3)):
The above recursive approach has overlapping subproblems, leading to redundant computations thereby resulting in exponential time complexity. This redundant computation can be solved by using Dynamic programming approach.
Here, we can use two 2D array C[][] and P[][], for storing the computed result.
- C[i][j] stores the minimum number of cuts needed for the substring str[i..j],
- while P[i][j] stores whether the substring str[i..j] is a palindrome or not.
- It starts with smaller substrings and gradually builds up to the entire string.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
int minPalPartion(string str)
{
int n = str.length();
int C[n][n];
bool P[n][n];
for ( int i = 0; i < n; i++) {
P[i][i] = true ;
C[i][i] = 0;
}
for ( int L = 2; L <= n; L++) {
for ( int i = 0; i < n - L + 1; i++) {
int j = i + L - 1;
if (L == 2)
P[i][j] = (str[i] == str[j]);
else
P[i][j]
= (str[i] == str[j]) && P[i + 1][j - 1];
if (P[i][j] == true )
C[i][j] = 0;
else {
C[i][j] = INT_MAX;
for ( int k = i; k <= j - 1; k++)
C[i][j] = min(
C[i][j], C[i][k] + C[k + 1][j] + 1);
}
}
}
return C[0][n - 1];
}
int main()
{
string str = "ababbbabbababa" ;
cout << "Min cuts needed for Palindrome"
" Partitioning is "
<< minPalPartion(str);
return 0;
}
|
C
#include <limits.h>
#include <stdio.h>
#include <string.h>
int min( int a, int b) { return (a < b) ? a : b; }
int minPalPartion( char * str)
{
int n = strlen (str);
int C[n][n];
bool P[n][n];
int i, j, k, L;
for (i = 0; i < n; i++) {
P[i][i] = true ;
C[i][i] = 0;
}
for (L = 2; L <= n; L++) {
for (i = 0; i < n - L + 1; i++) {
j = i + L - 1;
if (L == 2)
P[i][j] = (str[i] == str[j]);
else
P[i][j]
= (str[i] == str[j]) && P[i + 1][j - 1];
if (P[i][j] == true )
C[i][j] = 0;
else {
C[i][j] = INT_MAX;
for (k = i; k <= j - 1; k++)
C[i][j] = min(
C[i][j], C[i][k] + C[k + 1][j] + 1);
}
}
}
return C[0][n - 1];
}
int main()
{
char str[] = "ababbbabbababa" ;
printf (
"Min cuts needed for Palindrome Partitioning is %d" ,
minPalPartion(str));
return 0;
}
|
Java
public class GFG {
static int minPalPartion(String str)
{
int n = str.length();
int [][] C = new int [n][n];
boolean [][] P = new boolean [n][n];
int i, j, k, L;
for (i = 0 ; i < n; i++) {
P[i][i] = true ;
C[i][i] = 0 ;
}
for (L = 2 ; L <= n; L++) {
for (i = 0 ; i < n - L + 1 ; i++) {
j = i + L - 1 ;
if (L == 2 )
P[i][j]
= (str.charAt(i) == str.charAt(j));
else
P[i][j]
= (str.charAt(i) == str.charAt(j))
&& P[i + 1 ][j - 1 ];
if (P[i][j] == true )
C[i][j] = 0 ;
else {
C[i][j] = Integer.MAX_VALUE;
for (k = i; k <= j - 1 ; k++)
C[i][j] = Integer.min(
C[i][j],
C[i][k] + C[k + 1 ][j] + 1 );
}
}
}
return C[ 0 ][n - 1 ];
}
public static void main(String args[])
{
String str = "ababbbabbababa" ;
System.out.println( "Min cuts needed for "
+ "Palindrome Partitioning is "
+ minPalPartion(str));
}
}
|
Python3
def minPalPartion( str ):
n = len ( str )
C = [[ 0 for i in range (n)]
for i in range (n)]
P = [[ False for i in range (n)]
for i in range (n)]
j = 0
k = 0
L = 0
for i in range (n):
P[i][i] = True
C[i][i] = 0
for L in range ( 2 , n + 1 ):
for i in range (n - L + 1 ):
j = i + L - 1
if L = = 2 :
P[i][j] = ( str [i] = = str [j])
else :
P[i][j] = (( str [i] = = str [j]) and
P[i + 1 ][j - 1 ])
if P[i][j] = = True :
C[i][j] = 0
else :
C[i][j] = 100000000
for k in range (i, j):
C[i][j] = min (C[i][j], C[i][k] +
C[k + 1 ][j] + 1 )
return C[ 0 ][n - 1 ]
str = "ababbbabbababa"
print ( 'Min cuts needed for Palindrome Partitioning is' ,
minPalPartion( str ))
|
C#
using System;
class GFG {
static int minPalPartion(String str)
{
int n = str.Length;
int [, ] C = new int [n, n];
bool [, ] P = new bool [n, n];
int i, j, k, L;
for (i = 0; i < n; i++) {
P[i, i] = true ;
C[i, i] = 0;
}
for (L = 2; L <= n; L++) {
for (i = 0; i < n - L + 1; i++) {
j = i + L - 1;
if (L == 2)
P[i, j] = (str[i] == str[j]);
else
P[i, j] = (str[i] == str[j])
&& P[i + 1, j - 1];
if (P[i, j] == true )
C[i, j] = 0;
else {
C[i, j] = int .MaxValue;
for (k = i; k <= j - 1; k++)
C[i, j] = Math.Min(
C[i, j],
C[i, k] + C[k + 1, j] + 1);
}
}
}
return C[0, n - 1];
}
public static void Main()
{
String str = "ababbbabbababa" ;
Console.Write( "Min cuts needed for "
+ "Palindrome Partitioning is "
+ minPalPartion(str));
}
}
|
Javascript
<script>
function minPalPartion( str)
{
var n = str.length;
var C = Array(n).fill().map(()=>Array(n).fill(0));
var P = Array(n).fill().map(()=>Array(n).fill( false ));
var i, j, k, L;
for (i = 0; i < n; i++) {
P[i][i] = true ;
C[i][i] = 0;
}
for (L = 2; L <= n; L++) {
for (i = 0; i < n - L + 1; i++) {
j = i + L - 1;
if (L == 2)
P[i][j] = (str.charAt(i) == str.charAt(j));
else
P[i][j] = (str.charAt(i) == str.charAt(j)) && P[i + 1][j - 1];
if (P[i][j] == true )
C[i][j] = 0;
else {
C[i][j] = Number.MAX_VALUE;
for (k = i; k <= j - 1; k++)
C[i][j] = Math.min(C[i][j], C[i][k] + C[k + 1][j] + 1);
}
}
}
return C[0][n - 1];
}
var str = "ababbbabbababa" ;
document.write( "Min cuts needed for " + "Palindrome Partitioning is " + minPalPartion(str));
</script>
|
PHP
<?php
function minPalPartion( $str )
{
$n = strlen ( $str );
$C = array_fill (0, $n , array_fill (0, $n , NULL));
$P = array_fill (false, $n , array_fill (false, $n , NULL));
for ( $i =0; $i < $n ; $i ++)
{
$P [ $i ][ $i ] = true;
$C [ $i ][ $i ] = 0;
}
for ( $L =2; $L <= $n ; $L ++)
{
for ( $i =0; $i < $n - $L +1; $i ++)
{
$j = $i + $L -1;
if ( $L == 2)
$P [ $i ][ $j ] = ( $str [ $i ] == $str [ $j ]);
else
$P [ $i ][ $j ] = ( $str [ $i ] == $str [ $j ]) && $P [ $i +1][ $j -1];
if ( $P [ $i ][ $j ] == true)
$C [ $i ][ $j ] = 0;
else
{
$C [ $i ][ $j ] = PHP_INT_MAX;
for ( $k = $i ; $k <= $j -1; $k ++)
$C [ $i ][ $j ] = min ( $C [ $i ][ $j ], $C [ $i ][ $k ] + $C [ $k +1][ $j ]+1);
}
}
}
return $C [0][ $n -1];
}
$str = "ababbbabbababa" ;
echo "Min cuts needed for Palindrome Partitioning is "
.minPalPartion( $str );
return 0;
?>
|
Output
Min cuts needed for Palindrome Partitioning is 3
Time Complexity: O(n3)
Auxiliary Space: O(n2)
Dynamic Programming Approach for Palindrome Partitioning in (O(n2)):
The problem can be solved by finding the suffix starting from j and ending at index i, (1 <= j <= i <= n – 1), which are palindromes. Hence, we can make a cut here that requires 1 + min cut from rest substring [0, j – 1]. For all such palindromic suffixes starting at j and ending at i, keep minimising in minCutDp[i]. Similarly, we need to compute results for all such i. (1 <= i <= n – 1) and finally, minCutDp[n – 1] will be the minimum number of cuts needed for palindrome partitioning of the given string.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
bool generatePalindrome(string& s,
vector<vector< bool > >& pal)
{
int n = s.size();
for ( int i = 0; i < n; i++) {
pal[i][i] = true ;
}
for ( int len = 2; len <= n; len++) {
for ( int i = 0; i <= n - len; i++) {
int j = i + len - 1;
if (s[i] == s[j]
&& (len == 2 || pal[i + 1][j - 1])) {
pal[i][j] = true ;
}
}
}
}
int minCut(string s)
{
if (s.empty())
return 0;
int n = s.size();
vector<vector< bool > > pal(n, vector< bool >(n, false ));
generatePalindrome(s, pal);
vector< int > minCutDp(n, INT_MAX);
minCutDp[0] = 0;
for ( int i = 1; i < n; i++) {
if (pal[0][i]) {
minCutDp[i] = 0;
}
else {
for ( int j = i; j >= 1; j--) {
if (pal[j][i]) {
if (minCutDp[j - 1] + 1 < minCutDp[i])
minCutDp[i] = minCutDp[j - 1] + 1;
}
}
}
}
return minCutDp[n - 1];
}
int main()
{
string str = "ababbbabbababa" ;
int cuts = minCut(str);
cout << "Minimum cuts required: " << cuts << endl;
return 0;
}
|
Java
import java.util.Arrays;
public class GFG {
static boolean generatePalindrome(String s,
boolean [][] pal)
{
int n = s.length();
for ( int i = 0 ; i < n; i++) {
pal[i][i] = true ;
}
for ( int len = 2 ; len <= n; len++) {
for ( int i = 0 ; i <= n - len; i++) {
int j = i + len - 1 ;
if (s.charAt(i) == s.charAt(j)
&& (len == 2 || pal[i + 1 ][j - 1 ])) {
pal[i][j] = true ;
}
}
}
return true ;
}
static int minCut(String s)
{
if (s.isEmpty())
return 0 ;
int n = s.length();
boolean [][] pal = new boolean [n][n];
generatePalindrome(s, pal);
int [] minCutDp = new int [n];
Arrays.fill(minCutDp, Integer.MAX_VALUE);
minCutDp[ 0 ] = 0 ;
for ( int i = 1 ; i < n; i++) {
if (pal[ 0 ][i]) {
minCutDp[i] = 0 ;
}
else {
for ( int j = i; j >= 1 ; j--) {
if (pal[j][i]) {
if (minCutDp[j - 1 ] + 1
< minCutDp[i])
minCutDp[i]
= minCutDp[j - 1 ] + 1 ;
}
}
}
}
return minCutDp[n - 1 ];
}
public static void main(String[] args)
{
String str = "ababbbabbababa" ;
int cuts = minCut(str);
System.out.println( "Minimum cuts required: "
+ cuts);
}
}
|
Python3
def generate_palindrome(s, pal):
n = len (s)
for i in range (n):
pal[i][i] = True
for length in range ( 2 , n + 1 ):
for i in range (n - length + 1 ):
j = i + length - 1
if s[i] = = s[j] and (length = = 2 or pal[i + 1 ][j - 1 ]):
pal[i][j] = True
def min_cut(s):
if not s:
return 0
n = len (s)
pal = [[ False ] * n for _ in range (n)]
generate_palindrome(s, pal)
min_cut_dp = [ float ( 'inf' )] * n
min_cut_dp[ 0 ] = 0
for i in range ( 1 , n):
if pal[ 0 ][i]:
min_cut_dp[i] = 0
else :
for j in range (i, 0 , - 1 ):
if pal[j][i]:
if min_cut_dp[j - 1 ] + 1 < min_cut_dp[i]:
min_cut_dp[i] = min_cut_dp[j - 1 ] + 1
return min_cut_dp[n - 1 ]
if __name__ = = "__main__" :
str = "ababbbabbababa"
cuts = min_cut( str )
print ( "Minimum cuts required:" , cuts)
|
C#
using System;
class Program {
static void GeneratePalindrome( string s, bool [, ] pal)
{
int n = s.Length;
for ( int i = 0; i < n; i++) {
pal[i, i] = true ;
}
for ( int len = 2; len <= n; len++) {
for ( int i = 0; i <= n - len; i++) {
int j = i + len - 1;
if (s[i] == s[j]
&& (len == 2 || pal[i + 1, j - 1])) {
pal[i, j] = true ;
}
}
}
}
static int MinCut( string s)
{
if ( string .IsNullOrEmpty(s))
return 0;
int n = s.Length;
bool [, ] pal = new bool [n, n];
GeneratePalindrome(s, pal);
int [] minCutDp = new int [n];
for ( int i = 0; i < n; i++) {
minCutDp[i] = int .MaxValue;
}
minCutDp[0] = 0;
for ( int i = 1; i < n; i++) {
if (pal[0, i]) {
minCutDp[i] = 0;
}
else {
for ( int j = i; j >= 1; j--) {
if (pal[j, i]) {
if (minCutDp[j - 1] + 1
< minCutDp[i])
minCutDp[i]
= minCutDp[j - 1] + 1;
}
}
}
}
return minCutDp[n - 1];
}
static void Main()
{
string str = "ababbbabbababa" ;
int cuts = MinCut(str);
Console.WriteLine( "Minimum cuts required: " + cuts);
}
}
|
Javascript
function generatePalindrome(s, pal) {
const n = s.length;
for (let i = 0; i < n; i++) {
pal[i][i] = true ;
}
for (let len = 2; len <= n; len++) {
for (let i = 0; i <= n - len; i++) {
const j = i + len - 1;
if (s[i] === s[j] && (len === 2 || pal[i + 1][j - 1])) {
pal[i][j] = true ;
}
}
}
}
function minCut(s) {
if (!s) return 0;
const n = s.length;
const pal = Array.from({ length: n }, () => Array(n).fill( false ));
generatePalindrome(s, pal);
const minCutDp = Array(n).fill(Infinity);
minCutDp[0] = 0;
for (let i = 1; i < n; i++) {
if (pal[0][i]) {
minCutDp[i] = 0;
} else {
for (let j = i; j >= 1; j--) {
if (pal[j][i]) {
if (minCutDp[j - 1] + 1 < minCutDp[i]) {
minCutDp[i] = minCutDp[j - 1] + 1;
}
}
}
}
}
return minCutDp[n - 1];
}
const str = "abbac" ;
const cuts = minCut(str);
document.write( "Minimum cuts required:" , cuts);
|
Output
Minimum cuts required: 3
Time Complexity: O(n2)
Auxiliary Space: O(n2)
Feeling lost in the world of random DSA topics, wasting time without progress? It's time for a change! Join our DSA course, where we'll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 geeks!
Last Updated :
02 Oct, 2023
Like Article
Save Article