Palindrome Partitioning | DP-17

Given a string, a partitioning of the string is a palindrome partitioning if every substring of the partition is a palindrome. For example, “aba|b|bbabb|a|b|aba” is a palindrome partitioning of “ababbbabbababa”. Determine the fewest cuts needed for palindrome partitioning of a given string. For example, minimum 3 cuts are needed for “ababbbabbababa”. The three cuts are “a|babbbab|b|ababa”. If a string is palindrome, then minimum 0 cuts are needed. If a string of length n containing all different characters, then minimum n-1 cuts are needed.
palindrome-partitioning



This problem is a variation of Matrix Chain Multiplication problem. If the string is palindrome, then we simply return 0. Else, like the Matrix Chain Multiplication problem, we try making cuts at all possible places, recursively calculate the cost for each cut and return the minimum value.

Let the given string be str and minPalPartion() be the function that returns the fewest cuts needed for palindrome partitioning. following is the optimal substructure property.

// i is the starting index and j is the ending index. i must be passed as 0 and j as n-1
minPalPartion(str, i, j) = 0 if i == j. // When string is of length 1.
minPalPartion(str, i, j) = 0 if str[i..j] is palindrome.

// If none of the above conditions is true, then minPalPartion(str, i, j) can be 
// calculated recursively using the following formula.
minPalPartion(str, i, j) = Min { minPalPartion(str, i, k) + 1 +
                                 minPalPartion(str, k+1, j) } 
                           where k varies from i to j-1

Following is Dynamic Programming solution. It stores the solutions to subproblems in two arrays P[][] and C[][], and reuses the calculated values.

C/C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// Dynamic Programming Solution for Palindrome Partitioning Problem
#include <stdio.h>
#include <string.h>
#include <limits.h>
   
// A utility function to get minimum of two integers
int min (int a, int b) { return (a < b)? a : b; }
   
// Returns the minimum number of cuts needed to partition a string
// such that every part is a palindrome
int minPalPartion(char *str)
{
    // Get the length of the string
    int n = strlen(str);
   
    /* Create two arrays to build the solution in bottom up manner
       C[i][j] = Minimum number of cuts needed for palindrome partitioning
                 of substring str[i..j]
       P[i][j] = true if substring str[i..j] is palindrome, else false
       Note that C[i][j] is 0 if P[i][j] is true */
    int C[n][n];
    bool P[n][n];
   
    int i, j, k, L; // different looping variables
   
    // Every substring of length 1 is a palindrome
    for (i=0; i<n; i++)
    {
        P[i][i] = true;
        C[i][i] = 0;
    }
   
    /* L is substring length. Build the solution in bottom up manner by
       considering all substrings of length starting from 2 to n.
       The loop structure is same as Matrx Chain Multiplication problem (
    for (L=2; L<=n; L++)
    {
        // For substring of length L, set different possible starting indexes
        for (i=0; i<n-L+1; i++)
        {
            j = i+L-1; // Set ending index
   
            // If L is 2, then we just need to compare two characters. Else
            // need to check two corner characters and value of P[i+1][j-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 str[i..j] is palindrome, then C[i][j] is 0
            if (P[i][j] == true)
                C[i][j] = 0;
            else
            {
                // Make a cut at every possible location starting from i to j,
                // and get the minimum cost cut.
                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 the min cut value for complete string. i.e., str[0..n-1]
    return C[0][n-1];
}
   
// Driver program to test above function
int main()
{
   char str[] = "ababbbabbababa";
   printf("Min cuts needed for Palindrome Partitioning is %d",
           minPalPartion(str));
   return 0;
}

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java Code for Palindrome Partitioning 
// Problem
public class GFG 
{              
    // Returns the minimum number of cuts needed
    // to partition a string such that every 
    // part is a palindrome
    static int minPalPartion(String str)
    {
        // Get the length of the string
        int n = str.length();
        
        /* Create two arrays to build the solution
           in bottom up manner
           C[i][j] = Minimum number of cuts needed 
                     for palindrome partitioning
                     of substring str[i..j]
           P[i][j] = true if substring str[i..j] is
                     palindrome, else false
           Note that C[i][j] is 0 if P[i][j] is
           true */
        int[][] C = new int[n][n];
        boolean[][] P = new boolean[n][n];
        
        int i, j, k, L; // different looping variables
        
        // Every substring of length 1 is a palindrome
        for (i = 0; i < n; i++)
        {
            P[i][i] = true;
            C[i][i] = 0;
        }
        
        /* L is substring length. Build the solution in
         bottom up manner by considering all substrings
         of length starting from 2 to n. The loop 
         structure is same as Matrx Chain Multiplication
         problem (
        for (L = 2; L <= n; L++)
        {
            // For substring of length L, set different
            // possible starting indexes
            for (i = 0; i < n - L + 1; i++)
            {
                j = i + L - 1; // Set ending index
        
                // If L is 2, then we just need to 
                // compare two characters. Else need to
                // check two corner characters and value 
                // of P[i+1][j-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 str[i..j] is palindrome, then 
                // C[i][j] is 0
                if (P[i][j] == true)
                    C[i][j] = 0;
                else
                {
                    // Make a cut at every possible
                    // localtion starting from i to j,
                    // and get the minimum cost cut.
                    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 the min cut value for complete 
        // string. i.e., str[0..n-1]
        return C[0][n-1];
    }
        
    // Driver program to test above function
    public static void main(String args[])
    {
       String str = "ababbbabbababa";
       System.out.println("Min cuts needed for "+
                       "Palindrome Partitioning is "+
                          minPalPartion(str));
    }
}
// This code is contributed by Sumit Ghosh

chevron_right


python3

filter_none

edit
close

play_arrow

link
brightness_4
code

# Dynamic Programming Solution for 
# Palindrome Partitioning Problem 
  
# Returns the minimum number of 
# cuts needed to partition a string
# such that every part is a palindrome
def minPalPartion(str):
      
    # Get the length of the string
    n = len(str)
      
    # Create two arrays to build the 
    # solution in bottom up manner 
    # C[i][j] = Minimum number of cuts 
    #            needed for palindrome 
    #           partitioning of substring str[i..j] 
    # P[i][j] = true if substring str[i..j] 
    # is palindrome, else false. Note that
    # C[i][j] is 0 if P[i][j] is true 
    C = [[0 for i in range(n)] 
            for i in range(n)]
    P = [[False for i in range(n)] 
                for i in range(n)]
  
    # different looping variables
    j = 0
    k = 0
    L = 0
      
    # Every substring of length 
    # 1 is a palindrome 
    for i in range(n):
        P[i][i] = True
        C[i][i] = 0
          
    # L is substring length. Build the 
    # solution in bottom up manner by 
    # considering all substrings of 
    # length starting from 2 to n. 
    # The loop structure is same as 
    # Matrix Chain Multiplication problem  
    for L in range(2, n + 1):
          
        # For substring of length L, set 
        # different possible starting indexes 
        for i in range(n - L + 1):
            j = i + L - 1 # Set ending index 
              
            # If L is 2, then we just need to
            # compare two characters. Else 
            # need to check two corner characters
            # and value of P[i+1][j-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 str[i..j] is palindrome, 
            # then C[i][j] is 0
            if P[i][j] == True:
                C[i][j] = 0
            else:
                  
                # Make a cut at every possible 
                # location starting from i to j,
                #and get the minimum cost cut.
                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 the min cut value for 
    # complete string. i.e., str[0..n-1] 
    return C[0][n - 1]
  
# Driver code
str = "ababbbabbababa"
print ('Min cuts needed for Palindrome Partitioning is'
                                     minPalPartion(str))
                                        
# This code is contributed 
# by sahil shelangia

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# Code for Palindrome Partitioning 
// Problem
using System;
  
class GFG
{
    // Returns the minimum number of cuts needed
    // to partition a string such that every 
    // part is a palindrome
    static int minPalPartion(String str)
    {
        // Get the length of the string
        int n = str.Length;
          
        /* Create two arrays to build the solution
        in bottom up manner
        C[i][j] = Minimum number of cuts needed 
                    for palindrome partitioning
                    of substring str[i..j]
        P[i][j] = true if substring str[i..j] is
                    palindrome, else false
        Note that C[i][j] is 0 if P[i][j] is
        true */
        int[,] C = new int[n, n];
        bool[,] P = new bool[n, n];
          
        int i, j, k, L; // different looping variables
          
        // Every substring of length 1 is a palindrome
        for (i = 0; i < n; i++)
        {
            P[i, i] = true;
            C[i, i] = 0;
        }
          
        /* L is substring length. Build the solution in
        bottom up manner by considering all substrings
        of length starting from 2 to n. The loop 
        structure is same as Matrx Chain Multiplication
        problem (
        for (L = 2; L <= n; L++)
        {
            // For substring of length L, set different
            // possible starting indexes
            for (i = 0; i < n - L + 1; i++)
            {
                j = i + L - 1; // Set ending index
          
                // If L is 2, then we just need to 
                // compare two characters. Else need to
                // check two corner characters and value 
                // of P[i+1][j-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 str[i..j] is palindrome, then 
                // C[i][j] is 0
                if (P[i, j] == true)
                    C[i, j] = 0;
                else
                {
                    // Make a cut at every possible
                    // localtion starting from i to j,
                    // and get the minimum cost cut.
                    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 the min cut value for complete 
        // string. i.e., str[0..n-1]
        return C[0, n - 1];
    }
          
    // Driver program 
    public static void Main()
    {
    String str = "ababbbabbababa";
    Console.Write("Min cuts needed for "+
                  "Palindrome Partitioning is "+
                  minPalPartion(str));
    }
}
  
// This code is contributed by Sam007

chevron_right



Output:

Min cuts needed for Palindrome Partitioning is 3 

Time Complexity: O(n3)

An optimization to above approach
In above approach, we can calculate minimum cut while finding all palindromic substring. If we find all palindromic substring 1st and then we calculate minimum cut, time complexity will reduce to O(n2).
Thanks for Vivek for suggesting this optimization.

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// Dynamic Programming Solution for Palindrome Partitioning Problem
#include <stdio.h>
#include <string.h>
#include <limits.h>
   
// A utility function to get minimum of two integers
int min (int a, int b) { return (a < b)? a : b; }
   
// Returns the minimum number of cuts needed to partition a string
// such that every part is a palindrome
int minPalPartion(char *str)
{
    // Get the length of the string
    int n = strlen(str);
   
    /* Create two arrays to build the solution in bottom up manner
       C[i] = Minimum number of cuts needed for palindrome partitioning
                 of substring str[0..i]
       P[i][j] = true if substring str[i..j] is palindrome, else false
       Note that C[i] is 0 if P[0][i] is true */
    int C[n];
    bool P[n][n];
   
    int i, j, k, L; // different looping variables
   
    // Every substring of length 1 is a palindrome
    for (i=0; i<n; i++)
    {
        P[i][i] = true;
    }
   
    /* L is substring length. Build the solution in bottom up manner by
       considering all substrings of length starting from 2 to n. */
    for (L=2; L<=n; L++)
    {
        // For substring of length L, set different possible starting indexes
        for (i=0; i<n-L+1; i++)
        {
            j = i+L-1; // Set ending index
   
            // If L is 2, then we just need to compare two characters. Else
            // need to check two corner characters and value of P[i+1][j-1]
            if (L == 2)
                P[i][j] = (str[i] == str[j]);
            else
                P[i][j] = (str[i] == str[j]) && P[i+1][j-1];
        }
    }
  
    for (i=0; i<n; i++)
    {
        if (P[0][i] == true)
            C[i] = 0;
        else
        {
            C[i] = INT_MAX;
            for(j=0;j<i;j++)
            {
                if(P[j+1][i] == true && 1+C[j]<C[i])
                    C[i]=1+C[j];
            }
        }
    }
   
    // Return the min cut value for complete string. i.e., str[0..n-1]
    return C[n-1];
}
   
// Driver program to test above function
int main()
{
   char str[] = "ababbbabbababa";
   printf("Min cuts needed for Palindrome Partitioning is %d",
           minPalPartion(str));
   return 0;
}

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java Code for Palindrome Partitioning 
// Problem
public class GFG 
{            
    // Returns the minimum number of cuts needed
    // to partition a string such that every part
    // is a palindrome
    static int minPalPartion(String str)
    {
        // Get the length of the string
        int n = str.length();
        
        /* Create two arrays to build the solution
        in bottom up manner
           C[i] = Minimum number of cuts needed for
           palindrome partitioning of substring
           str[0..i]
           P[i][j] = true if substring str[i..j] is 
           palindrome, else false
           Note that C[i] is 0 if P[0][i] is true */
        int[] C = new int[n];
        boolean[][] P = new boolean[n][n];
        
        int i, j, k, L; // different looping variables
        
        // Every substring of length 1 is a palindrome
        for (i = 0; i < n; i++)
        {
            P[i][i] = true;
        }
        
        /* L is substring length. Build the solution 
        in bottom up manner by considering all substrings 
        of length starting from 2 to n. */
        for (L = 2; L <= n; L++)
        {
            // For substring of length L, set different 
            // possible starting indexes
            for (i = 0; i < n - L + 1; i++)
            {
                j = i + L - 1; // Set ending index
        
                // If L is 2, then we just need to 
                // compare two characters. Else need to 
                // check two corner characters and value
                // of P[i+1][j-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];
            }
        }
       
        for (i = 0; i < n; i++)
        {
            if (P[0][i] == true)
                C[i] = 0;
            else
            {
                C[i] = Integer.MAX_VALUE;
                for(j = 0; j < i; j++)
                {
                    if(P[j+1][i] == true && 1 +
                                 C[j] < C[i])
                        C[i] = 1 + C[j];
                }
            }
        }
        
        // Return the min cut value for complete
        // string. i.e., str[0..n-1]
        return C[n-1];
    }
      
    // Driver program to test above function
    public static void main(String args[])
    {
       String str = "ababbbabbababa";
       System.out.println("Min cuts needed for "+
                          "Palindrome Partitioning"+
                          " is "+ minPalPartion(str));
    }
}
// This code is contributed by Sumit Ghosh

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# Code for Palindrome Partitioning 
// Problem
using System;
  
class GFG
{
              
    // Returns the minimum number of cuts needed
    // to partition a string such that every part
    // is a palindrome
    static int minPalPartion(String str)
    {
        // Get the length of the string
        int n = str.Length;
          
        /* Create two arrays to build the solution
        in bottom up manner
        C[i] = Minimum number of cuts needed for
        palindrome partitioning of substring
        str[0..i]
        P[i][j] = true if substring str[i..j] is 
        palindrome, else false
        Note that C[i] is 0 if P[0][i] is true */
        int[] C = new int[n];
        bool[,] P = new bool[n,n];
          
        int i, j, L; // different looping variables
          
        // Every substring of length 1 is a palindrome
        for (i = 0; i < n; i++)
        {
            P[i,i] = true;
        }
          
        /* L is substring length. Build the solution 
        in bottom up manner by considering all substrings 
        of length starting from 2 to n. */
        for (L = 2; L <= n; L++)
        {
            // For substring of length L, set different 
            // possible starting indexes
            for (i = 0; i < n - L + 1; i++)
            {
                j = i + L - 1; // Set ending index
          
                // If L is 2, then we just need to 
                // compare two characters. Else need to 
                // check two corner characters and value
                // of P[i+1][j-1]
                if (L == 2)
                    P[i,j] = (str[i] == str[j]);
                else
                    P[i,j] = (str[i] == str[j]) && P[i+1,j-1];
            }
        }
      
        for (i = 0; i < n; i++)
        {
            if (P[0,i] == true)
                C[i] = 0;
            else
            {
                C[i] = int.MaxValue;
                for(j = 0; j < i; j++)
                {
                    if(P[j+1,i] == true && 1 + C[j] < C[i])
                        C[i] = 1 + C[j];
                }
            }
        }
          
        // Return the min cut value for complete
        // string. i.e., str[0..n-1]
        return C[n-1];
    }
      
    // Driver program 
    public static void Main()
    {
    String str = "ababbbabbababa";
    Console.Write("Min cuts needed for "+
                        "Palindrome Partitioning"+
                        " is "+ minPalPartion(str));
    }
}
  
// This code is contributed by Sam007

chevron_right



Output:

Min cuts needed for Palindrome Partitioning is 3 

Time Complexity: O(n2)

Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.



My Personal Notes arrow_drop_up

Improved By : sahilshelangia