Minimum insertions to form a palindrome (original) (raw)

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

**Examples:

**Input: s = "geeks"
**Output: 3
**Explanation: "skgeegks" is a palindromic string, which requires 3 insertions.

**Input: s= "abcd"
**Output: 3
**Explanation: "abcdcba" is a palindromic string.

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

Table of Content

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

Let minimum number of insertions in the string **str[l…..h] be findMinInsertions(str[l…..h]). It can be recursively defined as.

C++ `

// C++ approach to find Minimum // insertions to form a palindrome #include<bits/stdc++.h> using namespace std;

// Recursive function to find
// minimum number of insertions int minRecur(string &s, int l, int h) {

  // Base case
if (l >= h) return 0;

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

  // Insert at begining or insert at end
  return min(minRecur(s, l + 1, h), 
           minRecur(s, l, h - 1)) + 1;

}

int findMinInsertions(string &s) { return minRecur(s, 0, s.size() - 1); }

int main() { string s = "geeks"; cout << findMinInsertions(s); return 0; }

Java

// Java approach to find Minimum // insertions to form a palindrome class GfG {

// Recursive function to find  
// minimum number of insertions
static int minRecur(String s, int l, int h) {
  
    // Base case
    if (l >= h) return 0;
  
    // if first and last char are same 
    // then no need to insert element
    if (s.charAt(l) == s.charAt(h)) {
        return minRecur(s, l + 1, h - 1);
    }
  
    // Insert at begining or insert at end
    return Math.min(minRecur(s, l + 1, h), 
                    minRecur(s, l, h - 1)) + 1;
}

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

public static void main(String[] args) {
    String s = "geeks";
    System.out.println(findMinInsertions(s));
}

}

Python

Python approach to find Minimum

insertions to form a palindrome

Recursive function to find

minimum number of insertions

def minRecur(s, l, h):

# Base case
if l >= h:
    return 0

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

# Insert at begining or insert at end
return min(minRecur(s, l + 1, h), 
           minRecur(s, l, h - 1)) + 1

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

if name == "main": s = "geeks" print(findMinInsertions(s))

C#

// C# approach to find Minimum // insertions to form a palindrome using System;

class GfG {

// Recursive function to find  
// minimum number of insertions
static int minRecur(string s, int l, int h) {
  
    // Base case
    if (l >= h) return 0;
  
    // if first and last char are same 
    // then no need to insert element
    if (s[l] == s[h]) {
        return minRecur(s, l + 1, h - 1);
    }
  
    // Insert at begining or insert at end
    return Math.Min(minRecur(s, l + 1, h), 
                    minRecur(s, l, h - 1)) + 1;
}

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

static void Main(string[] args) {
    string s = "geeks";
    Console.WriteLine(findMinInsertions(s));
}

}

JavaScript

// JavaScript approach to find Minimum // insertions to form a palindrome

// Recursive function to find
// minimum number of insertions function minRecur(s, l, h) {

// Base case
if (l >= h) return 0;

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

// Insert at begining or insert at end
return Math.min(minRecur(s, l + 1, h), 
                minRecur(s, l, h - 1)) + 1;

}

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

const s = "geeks"; console.log(findMinInsertions(s));

`

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++ approach to find Minimum // insertions to form a palindrome #include<bits/stdc++.h> using namespace std;

// Recursive function to find
// minimum number of insertions int minRecur(string &s, int l, int h, vector<vector> &memo) {

  // Base case
if (l >= h) return 0;

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

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

  // Insert at begining or insert at end
  return memo[l][h] = min(minRecur(s, l + 1, h, memo), 
           minRecur(s, l, h - 1, memo)) + 1;

}

int findMinInsertions(string &s) { int n = s.length(); vector<vector> memo(n, vector(n, -1));

 return minRecur(s, 0, n - 1, memo);

}

int main() { string s = "geeks"; cout << findMinInsertions(s); return 0; }

Java

// Java approach to find Minimum // insertions to form a palindrome class GfG {

// Recursive function to find  
// minimum number of insertions
static int minRecur(String s, int l, int h, int[][] memo) {
  
    // Base case
    if (l >= h) return 0;
    
    // If value is memoized 
    if (memo[l][h] != -1) return memo[l][h];
  
    // if first and last char are same 
    // then no need to insert element
    if (s.charAt(l) == s.charAt(h)) {
        return memo[l][h] = minRecur(s, l + 1, h - 1, memo);
    }
  
    // Insert at begining or insert at end
    return memo[l][h] = Math.min(minRecur(s, l + 1, h, memo), 
                                 minRecur(s, l, h - 1, memo)) + 1;
}

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

public static void main(String[] args) {
    String s = "geeks";
    System.out.println(findMinInsertions(s));
}

}

Python

Python approach to find Minimum

insertions to form a palindrome

Recursive function to find

minimum number of insertions

def minRecur(s, l, h, memo):

# Base case
if l >= h:
    return 0

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

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

# Insert at begining or insert at end
memo[l][h] = min(minRecur(s, l + 1, h, memo), 
                 minRecur(s, l, h - 1, memo)) + 1
return memo[l][h]

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

if name == "main": s = "geeks" print(findMinInsertions(s))

C#

// C# approach to find Minimum // insertions to form a palindrome using System;

class GfG {

// Recursive function to find  
// minimum number of insertions
static int minRecur(string s, int l, int h, int[,] memo) {
  
    // Base case
    if (l >= h) return 0;

    // If value is memoized 
    if (memo[l, h] != -1) return memo[l, h];
  
    // if first and last char are same 
    // then no need to insert element
    if (s[l] == s[h]) {
        return memo[l, h] = minRecur(s, l + 1, h - 1, memo);
    }
  
    // Insert at begining or insert at end
    return memo[l, h] = Math.Min(minRecur(s, l + 1, h, memo), 
                                 minRecur(s, l, h - 1, memo)) + 1;
}

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

static void Main(string[] args) {
    string s = "geeks";
    Console.WriteLine(findMinInsertions(s));
}

}

JavaScript

// JavaScript approach to find Minimum // insertions to form a palindrome

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

// Base case
if (l >= h) return 0;

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

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

// Insert at begining or insert at end
return memo[l][h] = Math.min(minRecur(s, l + 1, h, memo), 
                             minRecur(s, l, h - 1, memo)) + 1;

}

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

const s = "geeks"; console.log(findMinInsertions(s));

`

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:

**Recursive Case:

C++ `

// C++ approach to find Minimum // insertions to form a palindrome #include<bits/stdc++.h> using namespace std;

// Function to find minimum insertions // to make string palindrome int findMinInsertions(string &s) { int n = s.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 (s[l] == s[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 s = "geeks"; cout << findMinInsertions(s); return 0; }

Java

// Java approach to find Minimum // insertions to form a palindrome class GfG {

// Function to find minimum insertions 
// to make string palindrome
static int findMinInsertions(String s) {
    int n = s.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 (s.charAt(l) == s.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 s = "geeks";
    System.out.println(findMinInsertions(s));
}

}

Python

Python approach to find Minimum

insertions to form a palindrome

Function to find minimum insertions

to make string palindrome

def findMinInsertions(s): n = len(s)

# 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 s[l] == s[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]

if name == "main": s = "geeks" print(findMinInsertions(s))

C#

// C# approach to find Minimum // insertions to form a palindrome using System;

class MainClass {

// Function to find minimum insertions 
// to make string palindrome
static int findMinInsertions(string s) {
    int n = s.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 (s[l] == s[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];
}

static void Main(string[] args) {
    string s = "geeks";
    Console.WriteLine(findMinInsertions(s));
}

}

JavaScript

// JavaScript approach to find Minimum // insertions to form a palindrome

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

// dp[i][j] will store the minimum number of insertions needed
// to convert str[i..j] into a palindrome
const dp = Array.from({ length: 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
        const h = l + len - 1;

        // If the characters at both ends are 
        // equal, no new insertions needed
        if (s[l] === s[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];

}

const s = "geeks"; console.log(findMinInsertions(s));

`

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++ `

// C++ approach to find Minimum // insertions to form a palindrome #include<bits/stdc++.h> using namespace std;

// Function to find minimum insertions // to make string palindrome int findMinInsertions(string &s) { int n = s.size(); vector 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 (s[l] == s[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 s = "geeks"; cout << findMinInsertions(s); return 0; }

Java

// Java approach to find Minimum // insertions to form a palindrome class GfG {

// Function to find minimum insertions 
// to make string palindrome
static int findMinInsertions(String s) {
    int n = s.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 (s.charAt(l) == s.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 s = "geeks";
    System.out.println(findMinInsertions(s));
}

}

Python

Python approach to find Minimum

insertions to form a palindrome

Function to find minimum insertions

to make string palindrome

def findMinInsertions(s): n = len(s) 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 s[l] == s[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]

if name == "main": s = "geeks" print(findMinInsertions(s))

C#

// C# approach to find Minimum // insertions to form a palindrome using System;

class GfG {

// Function to find minimum insertions 
// to make string palindrome
static int findMinInsertions(string s) {
    int n = s.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 (s[l] == s[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 s = "geeks";
    Console.WriteLine(findMinInsertions(s));
}

}

JavaScript

// JavaScript approach to find Minimum // insertions to form a palindrome

// Function to find minimum insertions // to make string palindrome function findMinInsertions(s) { const n = s.length; const 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 (s[l] === s[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];

}

const s = "geeks"; console.log(findMinInsertions(s));

`

**Related article: