Open In App

Minimum insertions to form a palindrome

Last Updated : 16 Nov, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

Given string str, the task is to find the minimum number of characters to be inserted to convert it to a palindrome.

Examples:

Input: str = abcd
Output: 3
Explanation: Here we can append 3 characters in the beginning, and the resultant string will be a palindrome (“dcbabcd”).

Input: str = aba
Output: 0
Explanation: Given string is already a palindrome hence no insertions are required.

Using Recursion – O(2^n) Time and O(n) Space

The idea is to use recursion and the problem can be broken down into three parts:

  1. Find the minimum number of insertions in the substring str[l+1,…….h].
  2. Find the minimum number of insertions in the substring str[l…….h-1].
  3. Find the minimum number of insertions in the substring str[l+1……h-1].

The minimum number of insertions in the string str[l…..h] can be given as:  

  • if str[l] is equal to str[h] findMinInsertions(str[l+1…..h-1])
  • otherwise, min(findMinInsertions(str[l…..h-1]), findMinInsertions(str[l+1…..h])) + 1
C++
// C++ Naive approach of finding minimum
// insertion to make string pelindrom

#include<bits/stdc++.h>
using namespace std;


// Recursive function to find  
// minimum number of insertions
int getMinPeliAns(string &str, int l, int h) {
  
  	// Base cases
    if (l > h) return INT_MAX;
    if (l == h) return 0;
    if (l == h - 1) return (str[l] == str[h])? 0 : 1;
  
  	// if first and last char are same 
  	// then no need to insert element
  	if(str[l] == str[h]) {
      	return getMinPeliAns(str, l + 1, h - 1);
    }
  
  	// Insert at begining or insert at end
  	return min(getMinPeliAns(str, l + 1, h), 
               getMinPeliAns(str, l, h - 1)) + 1;
}

int findMinInsertions(string &s) {
 	return getMinPeliAns(s, 0, s.size() - 1);
}
int main() {
    string str = "geeks";
    cout << findMinInsertions(str);
    return 0;
}
Java
// Java Naive approach of finding minimum
// insertion to make string palindrome

import java.util.*;

class GfG {
  
    // Recursive function to find  
    // minimum number of insertions
    static int getMinPeliAns(String str, int l, int h) {
      
        // Base cases
        if (l > h) return Integer.MAX_VALUE;
        if (l == h) return 0;
        if (l == h - 1) return (str.charAt(l) == str.charAt(h)) ? 0 : 1;

        // if first and last char are same 
        // then no need to insert element
        if (str.charAt(l) == str.charAt(h)) {
            return getMinPeliAns(str, l + 1, h - 1);
        }

        // Insert at beginning or insert at end
        return Math.min(getMinPeliAns(str, l + 1, h), 
                        getMinPeliAns(str, l, h - 1)) + 1;
    }

    static int findMinInsertions(String s) {
        return getMinPeliAns(s, 0, s.length() - 1);
    }

    public static void main(String[] args) {
        String str = "geeks";
        System.out.println(findMinInsertions(str));
    }
}
Python
# Python Naive approach of finding minimum
# insertion to make string palindrome

# Recursive function to find  
# minimum number of insertions
def getMinPeliAns(str, l, h):
  
    # Base cases
    if l > h:
        return float('inf')
    if l == h:
        return 0
    if l == h - 1:
        return 0 if str[l] == str[h] else 1

    # if first and last char are same 
    # then no need to insert element
    if str[l] == str[h]:
        return getMinPeliAns(str, l + 1, h - 1)

    # Insert at beginning or insert at end
    return min(getMinPeliAns(str, l + 1, h), 
               getMinPeliAns(str, l, h - 1)) + 1

def findMinInsertions(s):
    return getMinPeliAns(s, 0, len(s) - 1)

str = "geeks"
print(findMinInsertions(str))
C#
// C# Naive approach of finding minimum
// insertion to make string palindrome
using System;

class GfG {
  
    // Recursive function to find  
    // minimum number of insertions
    static int getMinPeliAns(string str, int l, int h) {
      
        // Base cases
        if (l > h) return int.MaxValue;
        if (l == h) return 0;
        if (l == h - 1) return (str[l] == str[h]) ? 0 : 1;

        // if first and last char are same 
        // then no need to insert element
        if (str[l] == str[h]) {
            return getMinPeliAns(str, l + 1, h - 1);
        }

        // Insert at beginning or insert at end
        return Math.Min(getMinPeliAns(str, l + 1, h), 
                        getMinPeliAns(str, l, h - 1)) + 1;
    }

    static int findMinInsertions(string s) {
        return getMinPeliAns(s, 0, s.Length - 1);
    }

     static void Main() {
        string str = "geeks";
        Console.WriteLine(findMinInsertions(str));
    }
}
JavaScript
// JavaScript Naive approach of finding minimum
// insertion to make string palindrome

// Recursive function to find  
// minimum number of insertions
function getMinPeliAns(str, l, h) {

    // Base cases
    if (l > h) return Number.MAX_SAFE_INTEGER;
    if (l === h) return 0;
    if (l === h - 1) return (str[l] === str[h]) ? 0 : 1;

    // if first and last char are same 
    // then no need to insert element
    if (str[l] === str[h]) {
        return getMinPeliAns(str, l + 1, h - 1);
    }

    // Insert at beginning or insert at end
    return Math.min(getMinPeliAns(str, l + 1, h), 
                    getMinPeliAns(str, l, h - 1)) + 1;
}

function findMinInsertions(s) {
    return getMinPeliAns(s, 0, s.length - 1);
}

let str = "geeks";
console.log(findMinInsertions(str));

Output
3

Using Top-Down DP (Memoization) – O(n^2) Time and O(n^2) Space

If we notice carefully, we can observe that the above recursive solution holds the following two properties of Dynamic Programming:

1. Optimal Substructure: The minimum number of insertions required to make the substring str[l…h] a palindrome depends on the optimal solutions of its subproblems. If str[l] is equal to str[h] then we call recursive call on l + 1 and h – 1 other we make two recursive call to get optimal answer.

2. Overlapping Subproblems: When using a recursive approach, we notice that certain subproblems are computed multiple times. To avoid this redundancy, we can use memoization by storing the results of already computed subproblems in a 2D array.

The problem involves changing two parameters: l (starting index) and h (ending index). Hence, we need to create a 2D array of size (n x n) to store the results, where n is the length of the string. By using this 2D array, we can efficiently reuse previously computed results and optimize the solution.

C++
// C++ Memoization approach of finding minimum
// insertion to make string pelindrom

#include<bits/stdc++.h>
using namespace std;


// Recursive function to find  
// minimum number of insertions
int getMinPeliAns(string &str, int l, int h, vector<vector<int>> &memo) {
  
  	// Base cases
    if (l > h) return INT_MAX;
    if (l == h) return 0;
    if (l == h - 1) return (str[l] == str[h])? 0 : 1;
  
  	// If the value is calculated previously
  	if(memo[l][h] != -1) return memo[l][h];
  
  	// if first and last char are same 
  	// then no need to insert element
  	if(str[l] == str[h]) {
      	return memo[l][h] = getMinPeliAns(str, l + 1, h - 1, memo);
    }
  
  	// Insert at begining or insert at end
  	return memo[l][h] = min(getMinPeliAns(str, l + 1, h, memo), 
               getMinPeliAns(str, l, h - 1, memo)) + 1;
}

int findMinInsertions(string &s) {
  	int n = s.size();
  	vector<vector<int>> memo(n + 1, vector<int> (n + 1, -1));
 	return getMinPeliAns(s, 0, s.size() - 1, memo);
}
int main() {
    string str = "geeks";
    cout << findMinInsertions(str);
    return 0;
}
Java
// Java Memoization approach of finding minimum
// insertion to make string palindrome
import java.util.*;

class GfG {
  
    // Recursive function to find  
    // minimum number of insertions
    static int getMinPeliAns(String str, int l, int h, int[][] memo) {
      
        // Base cases
        if (l > h) return Integer.MAX_VALUE;
        if (l == h) return 0;
        if (l == h - 1) return (str.charAt(l) == str.charAt(h)) ? 0 : 1;

        // If the value is calculated previously
        if (memo[l][h] != -1) return memo[l][h];

        // if first and last char are same 
        // then no need to insert element
        if (str.charAt(l) == str.charAt(h)) {
            return memo[l][h] = getMinPeliAns(str, l + 1, h - 1, memo);
        }

        // Insert at beginning or insert at end
        return memo[l][h] = Math.min(getMinPeliAns(str, l + 1, h, memo), 
                                     getMinPeliAns(str, l, h - 1, memo)) + 1;
    }

    static int findMinInsertions(String s) {
        int n = s.length();
        int[][] memo = new int[n + 1][n + 1];
        for (int[] row : memo) Arrays.fill(row, -1);
        return getMinPeliAns(s, 0, n - 1, memo);
    }

    public static void main(String[] args) {
        String str = "geeks";
        System.out.println(findMinInsertions(str));
    }
}
Python
# Python Memoization approach of finding minimum
# insertion to make string palindrome

# Recursive function to find  
# minimum number of insertions
def getMinPeliAns(str, l, h, memo):
  
    # Base cases
    if l > h:
        return float('inf')
    if l == h:
        return 0
    if l == h - 1:
        return 0 if str[l] == str[h] else 1

    # If the value is calculated previously
    if memo[l][h] != -1:
        return memo[l][h]

    # if first and last char are same 
    # then no need to insert element
    if str[l] == str[h]:
        memo[l][h] = getMinPeliAns(str, l + 1, h - 1, memo)
        return memo[l][h]

    # Insert at beginning or insert at end
    memo[l][h] = min(getMinPeliAns(str, l + 1, h, memo), 
                     getMinPeliAns(str, l, h - 1, memo)) + 1
    return memo[l][h]

def findMinInsertions(s):
    n = len(s)
    memo = [[-1 for _ in range(n + 1)] for _ in range(n + 1)]
    return getMinPeliAns(s, 0, n - 1, memo)

str = "geeks"
print(findMinInsertions(str))
C#
// C# Memoization approach of finding minimum
// insertion to make string palindrome
using System;

class GfG {
  
    // Recursive function to find  
    // minimum number of insertions
    static int getMinPeliAns(string str, int l, int h, int[,] memo) {
      
        // Base cases
        if (l > h) return int.MaxValue;
        if (l == h) return 0;
        if (l == h - 1) return (str[l] == str[h]) ? 0 : 1;

        // If the value is calculated previously
        if (memo[l, h] != -1) return memo[l, h];

        // if first and last char are same 
        // then no need to insert element
        if (str[l] == str[h]) {
            return memo[l, h] = getMinPeliAns(str, l + 1, h - 1, memo);
        }

        // Insert at beginning or insert at end
        return memo[l, h] = Math.Min(getMinPeliAns(str, l + 1, h, memo), 
                                     getMinPeliAns(str, l, h - 1, memo)) + 1;
    }

    static int findMinInsertions(string s) {
        int n = s.Length;
        int[,] memo = new int[n + 1, n + 1];
        for (int i = 0; i <= n; i++)
            for (int j = 0; j <= n; j++)
                memo[i, j] = -1;
        return getMinPeliAns(s, 0, n - 1, memo);
    }

    static void Main() {
        string str = "geeks";
        Console.WriteLine(findMinInsertions(str));
    }
}
JavaScript
// JavaScript Memoization approach of finding minimum
// insertion to make string palindrome

// Recursive function to find  
// minimum number of insertions
function getMinPeliAns(str, l, h, memo) {

    // Base cases
    if (l > h) return Number.MAX_SAFE_INTEGER;
    if (l === h) return 0;
    if (l === h - 1) return (str[l] === str[h]) ? 0 : 1;

    // If the value is calculated previously
    if (memo[l][h] !== -1) return memo[l][h];

    // if first and last char are same 
    // then no need to insert element
    if (str[l] === str[h]) {
        memo[l][h] = getMinPeliAns(str, l + 1, h - 1, memo);
        return memo[l][h];
    }

    // Insert at beginning or insert at end
    memo[l][h] = Math.min(getMinPeliAns(str, l + 1, h, memo), 
                          getMinPeliAns(str, l, h - 1, memo)) + 1;
    return memo[l][h];
}

function findMinInsertions(s) {
    const n = s.length;
    const memo = Array.from({ length: n + 1 }, () => Array(n + 1).fill(-1));
    return getMinPeliAns(s, 0, n - 1, memo);
}

let str = "geeks";
console.log(findMinInsertions(str));

Output
3

Using Bottom-Up DP (Tabulation) – O(n^2) Time and O(n^2) Space

The iterative approach for finding the minimum number of insertions needed to make a string palindrome follows a similar concept to the recursive solution but builds the solution in a bottom-up manner using a 2D dynamic programming table.

Base Case:

  • if l == h than dp[l][h] = 0. Where 0 <= l <= n – 1
  • If the substring has two characters (h == l + 1), we check if they are the same. If they are, dp[l][h] = 0, otherwise, dp[l][h] = 1.

Recursive Case:

  • If str[l] == str[h], then dp[l][h] = dp[l+1][h-1].
  • Otherwise, dp[l][h] = min(dp[l+1][h], dp[l][h-1]) + 1. 
C++
// C++ Iterative approach of finding minimum
// insertion to make string palindrome
#include <bits/stdc++.h>
using namespace std;

// Function to find minimum insertions 
// to make string palindrome
int findMinInsertions(string &str) {
    int n = str.size();
    
    // dp[i][j] will store the minimum number of insertions needed
    // to convert str[i..j] into a palindrome
    vector<vector<int>> dp(n, vector<int>(n, 0));

    // len is the length of the substring
    for (int len = 2; len <= n; len++) {
        for (int l = 0; l <= n - len; l++) {
          
          	// ending index of the current substring
            int h = l + len - 1; 

            // If the characters at both ends are 
          	// equal, no new insertions needed
            if (str[l] == str[h]) {
                dp[l][h] = dp[l + 1][h - 1];
            } else {
                // Insert at the beginning or at the end
                dp[l][h] = min(dp[l + 1][h], dp[l][h - 1]) + 1;
            }
        }
    }

    // The result is in dp[0][n-1] which 
  	// represents the entire string
    return dp[0][n - 1];
}

int main() {
    string str = "geeks";
    cout << findMinInsertions(str) << endl;
    return 0;
}
Java
// C++ Iterative approach of finding minimum
// insertion to make string palindrome
class GfG {

    // Function to find minimum insertions 
    // to make string palindrome
    static int findMinInsertions(String str) {
        int n = str.length();
        
        // dp[i][j] will store the minimum number of insertions needed
        // to convert str[i..j] into a palindrome
        int[][] dp = new int[n][n];

        // len is the length of the substring
        for (int len = 2; len <= n; len++) {
            for (int l = 0; l <= n - len; l++) {
              
                // ending index of the current substring
                int h = l + len - 1; 

                // If the characters at both ends are 
                // equal, no new insertions needed
                if (str.charAt(l) == str.charAt(h)) {
                    dp[l][h] = dp[l + 1][h - 1];
                } else {
                    // Insert at the beginning or at the end
                    dp[l][h] = Math.min(dp[l + 1][h], dp[l][h - 1]) + 1;
                }
            }
        }

        // The result is in dp[0][n-1] which 
        // represents the entire string
        return dp[0][n - 1];
    }

    public static void main(String[] args) {
        String str = "geeks";
        System.out.println(findMinInsertions(str));
    }
}
Python
# C++ Iterative approach of finding minimum
# insertion to make string palindrome

# Function to find minimum insertions 
# to make string palindrome
def findMinInsertions(str):
    n = len(str)

    # dp[i][j] will store the minimum number of insertions needed
    # to convert str[i..j] into a palindrome
    dp = [[0] * n for _ in range(n)]

    # len is the length of the substring
    for length in range(2, n + 1):
        for l in range(n - length + 1):
          
            # ending index of the current substring
            h = l + length - 1

            # If the characters at both ends are 
            # equal, no new insertions needed
            if str[l] == str[h]:
                dp[l][h] = dp[l + 1][h - 1]
            else:
                # Insert at the beginning or at the end
                dp[l][h] = min(dp[l + 1][h], dp[l][h - 1]) + 1

    # The result is in dp[0][n-1] which 
    # represents the entire string
    return dp[0][n - 1]

# Driver code
str = "geeks"
print(findMinInsertions(str))
C#
// C++ Iterative approach of finding minimum
// insertion to make string palindrome
using System;

class GfG {

    // Function to find minimum insertions 
    // to make string palindrome
    static int findMinInsertions(string str) {
        int n = str.Length;
        
        // dp[i][j] will store the minimum number of insertions needed
        // to convert str[i..j] into a palindrome
        int[,] dp = new int[n, n];

        // len is the length of the substring
        for (int len = 2; len <= n; len++) {
            for (int l = 0; l <= n - len; l++) {
              
                // ending index of the current substring
                int h = l + len - 1; 

                // If the characters at both ends are 
                // equal, no new insertions needed
                if (str[l] == str[h]) {
                    dp[l, h] = dp[l + 1, h - 1];
                } else {
                    // Insert at the beginning or at the end
                    dp[l, h] = Math.Min(dp[l + 1, h], dp[l, h - 1]) + 1;
                }
            }
        }

        // The result is in dp[0][n-1] which 
        // represents the entire string
        return dp[0, n - 1];
    }

    public static void Main(string[] args) {
        string str = "geeks";
        Console.WriteLine(findMinInsertions(str));
    }
}
JavaScript
// C++ Iterative approach of finding minimum
// insertion to make string palindrome

// Function to find minimum insertions 
// to make string palindrome
function findMinInsertions(str) {
    let n = str.length;

    // dp[i][j] will store the minimum number of insertions needed
    // to convert str[i..j] into a palindrome
    let dp = Array.from(Array(n), () => Array(n).fill(0));

    // len is the length of the substring
    for (let len = 2; len <= n; len++) {
        for (let l = 0; l <= n - len; l++) {
          
            // ending index of the current substring
            let h = l + len - 1; 

            // If the characters at both ends are 
            // equal, no new insertions needed
            if (str[l] === str[h]) {
                dp[l][h] = dp[l + 1][h - 1];
            } else {
                // Insert at the beginning or at the end
                dp[l][h] = Math.min(dp[l + 1][h], dp[l][h - 1]) + 1;
            }
        }
    }

    // The result is in dp[0][n-1] which 
    // represents the entire string
    return dp[0][n - 1];
}

// Driver code
const str = "geeks";
console.log(findMinInsertions(str));

Output
3

Using Space Optimized DP – O(n ^ 2) Time and O(n) Space

The idea is to reuse the array in such a way that we store the results for the previous row in the same array while iterating through the columns.

C++
// Optimized C++ approach of finding minimum
// insertions to make a string palindrome using 1D DP

#include <bits/stdc++.h>
using namespace std;

// Function to find minimum insertions to make string a palindrome
int findMinInsertions(string &str) {
    int n = str.size();
    vector<int> dp(n, 0);
    
    // Iterate over each character from right to left
    for (int l = n - 2; l >= 0; l--) {
      
      	// This represents dp[l+1][h-1] from the previous row
        int prev = 0; 
        for (int h = l + 1; h < n; h++) {
          
          	// Save current dp[h] before overwriting
            int temp = dp[h]; 
            
            if (str[l] == str[h]) {
              
              	// No new insertion needed if characters match
                dp[h] = prev; 
            } else {
              
              	// Take min of two cases + 1
                dp[h] = min(dp[h], dp[h - 1]) + 1; 
            }
            
          	// Update prev for the next column
            prev = temp; 
        }
    }
    
    return dp[n - 1];
}

int main() {
    string str = "geeks";
    cout << findMinInsertions(str) << endl;
    return 0;
}
Java
// Optimized C++ approach of finding minimum
// insertions to make a string palindrome using 1D DP
public class GfG {

    // Function to find minimum insertions to make string a palindrome
    static int findMinInsertions(String str) {
        int n = str.length();
        int[] dp = new int[n];

        // Iterate over each character from right to left
        for (int l = n - 2; l >= 0; l--) {

            // This represents dp[l+1][h-1] from the previous row
            int prev = 0;
            for (int h = l + 1; h < n; h++) {

                // Save current dp[h] before overwriting
                int temp = dp[h];

                if (str.charAt(l) == str.charAt(h)) {

                    // No new insertion needed if characters match
                    dp[h] = prev;
                } else {

                    // Take min of two cases + 1
                    dp[h] = Math.min(dp[h], dp[h - 1]) + 1;
                }

                // Update prev for the next column
                prev = temp;
            }
        }

        return dp[n - 1];
    }

    public static void main(String[] args) {
        String str = "geeks";
        System.out.println(findMinInsertions(str));
    }
}
Python
# Optimized C++ approach of finding minimum
# insertions to make a string palindrome using 1D DP

# Function to find minimum insertions to make string a palindrome
def findMinInsertions(str):
    n = len(str)
    dp = [0] * n

    # Iterate over each character from right to left
    for l in range(n - 2, -1, -1):

        # This represents dp[l+1][h-1] from the previous row
        prev = 0
        for h in range(l + 1, n):

            # Save current dp[h] before overwriting
            temp = dp[h]

            if str[l] == str[h]:

                # No new insertion needed if characters match
                dp[h] = prev
            else:

                # Take min of two cases + 1
                dp[h] = min(dp[h], dp[h - 1]) + 1

            # Update prev for the next column
            prev = temp

    return dp[n - 1]

# Driver code
str = "geeks"
print(findMinInsertions(str))
C#
// Optimized C++ approach of finding minimum
// insertions to make a string palindrome using 1D DP

using System;

class GfG {

    // Function to find minimum insertions to make string a palindrome
    static int findMinInsertions(string str) {
        int n = str.Length;
        int[] dp = new int[n];

        // Iterate over each character from right to left
        for (int l = n - 2; l >= 0; l--) {

            // This represents dp[l+1][h-1] from the previous row
            int prev = 0;
            for (int h = l + 1; h < n; h++) {

                // Save current dp[h] before overwriting
                int temp = dp[h];

                if (str[l] == str[h]) {

                    // No new insertion needed if characters match
                    dp[h] = prev;
                } else {

                    // Take min of two cases + 1
                    dp[h] = Math.Min(dp[h], dp[h - 1]) + 1;
                }

                // Update prev for the next column
                prev = temp;
            }
        }

        return dp[n - 1];
    }

    static void Main(string[] args) {
        string str = "geeks";
        Console.WriteLine(findMinInsertions(str));
    }
}
JavaScript
// Optimized C++ approach of finding minimum
// insertions to make a string palindrome using 1D DP

// Function to find minimum insertions to make string a palindrome
function findMinInsertions(str) {
    let n = str.length;
    let dp = new Array(n).fill(0);

    // Iterate over each character from right to left
    for (let l = n - 2; l >= 0; l--) {

        // This represents dp[l+1][h-1] from the previous row
        let prev = 0;
        for (let h = l + 1; h < n; h++) {

            // Save current dp[h] before overwriting
            let temp = dp[h];

            if (str[l] === str[h]) {

                // No new insertion needed if characters match
                dp[h] = prev;
            } else {

                // Take min of two cases + 1
                dp[h] = Math.min(dp[h], dp[h - 1]) + 1;
            }

            // Update prev for the next column
            prev = temp;
        }
    }

    return dp[n - 1];
}

// Driver code
const str = "geeks";
console.log(findMinInsertions(str));

Output
3

Related article: 



Next Article

Similar Reads