📌  相关文章
📜  组成字符串回文的最小删除数|套装2

📅  最后修改于: 2021-04-29 01:45:58             🧑  作者: Mango

给定字符串A,计算需要删除的最小字符数,以使结果字符串成为回文。

例子:

Input : baca
Output : 1

Input : geek
Output : 2

我们在下面的文章中讨论了一种方法。
构成字符串回文的最小删除数

下面的方法将使用修改后的Levenshtein距离。我们考虑修改的Levensthein(仅考虑删除)既包括原始字符串,也包括其反向字符串。

C++
// CPP program to find minimum deletions to make
// palindrome.
#include 
using namespace std;
  
  
int getLevenstein(string const& input)
{
    // Find reverse of input string
    string revInput(input.rbegin(), input.rend());
  
    // Create a DP table for storing edit distance
    // of string and reverse.
    int n = input.size();
    vector > dp(n + 1, vector(n + 1, -1));
    for (int i = 0; i <= n; ++i) {
        dp[0][i] = i;
        dp[i][0] = i;
    }
  
    // Find edit distance between input and revInput 
    // considering only delete operation.
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            if (input[i - 1] == revInput[j - 1]) 
                dp[i][j] = dp[i - 1][j - 1];            
            else 
                dp[i][j] = 1 + min({ dp[i - 1][j], dp[i][j - 1] });            
        }
    }
  
    /*Go from bottom left to top right and find the minimum*/
    int res = numeric_limits::max();
    for (int i = n, j = 0; i >= 0; --i, ++j) {
        res = min(res, dp[i][j]);
        if (i < n) 
            res = min(res, dp[i + 1][j]);        
        if (i > 0) 
            res = min(res, dp[i - 1][j]);        
    }
    return res;
}
  
// Driver code
int main()
{
    string input("myfirstgeekarticle");
    cout << getLevenstein(input);
    return 0;
}


Java
// Java program to find minimum deletions to make 
// palindrome.
import java.io.*;
import java.util.*;
  
class GFG 
{
  
    static int getLevenstein(StringBuilder input)
    {
        StringBuilder revInput = new StringBuilder(input);
  
        // Find reverse of input string
        revInput = revInput.reverse();
  
        // Create a DP table for storing edit distance
        // of string and reverse.
        int n = input.length();
        int[][] dp = new int[n + 1][n + 1];
        for (int i = 0; i <= n; ++i) 
        {
            dp[0][i] = i;
            dp[i][0] = i;
        }
  
        // Find edit distance between input and revInput
        // considering only delete operation.
        for (int i = 1; i <= n; ++i) 
        {
            for (int j = 1; j <= n; ++j) 
            {
                if (input.charAt(i - 1) == revInput.charAt(j - 1))
                    dp[i][j] = dp[i - 1][j - 1];
                else
                    dp[i][j] = 1 + Math.min(dp[i - 1][j], dp[i][j - 1]);
            }
        }
  
        /* Go from bottom left to top right and find the minimum */
        int res = Integer.MAX_VALUE;
        for (int i = n, j = 0; i >= 0; i--, j++) 
        {
            res = Math.min(res, dp[i][j]);
            if (i < n)
                res = Math.min(res, dp[i + 1][j]);
            if (i > 0)
                res = Math.min(res, dp[i - 1][j]);
        }
        return res;
    }
  
    // Driver Code
    public static void main(String[] args)
    {
        StringBuilder input = new StringBuilder("myfirstgeekarticle");
        System.out.println(getLevenstein(input));
    }
}
  
// This code is contributed by
// sanjeev2552


Python3
# Python3 program to find minimum deletions 
# to make palindrome.
INT_MAX = 99999999999
  
def getLevenstein(inpt):
  
    # Find reverse of input string
    revInput = inpt[::-1]
  
    # Create a DP table for storing  
    # edit distance of string and reverse.
    n = len(inpt)
    dp = [[-1 for _ in range(n + 1)] 
              for __ in range(n + 1)]
    for i in range(n + 1):
        dp[0][i] = i
        dp[i][0] = i
  
    # Find edit distance between 
    # input and revInput considering
    # only delete operation.
    for i in range(1, n + 1):
        for j in range(1, n + 1):
            if inpt[i - 1] == revInput[j - 1]:
                dp[i][j] = dp[i - 1][j - 1]
            else:
                dp[i][j] = 1 + min(dp[i - 1][j], 
                                   dp[i][j - 1])
  
    # Go from bottom left to top right
    # and find the minimum
    res = INT_MAX
    i, j = n, 0
    while i >= 0:
        res = min(res, dp[i][j])
        if i < n:
            res = min(res, dp[i + 1][j])
        if i > 0:
            res = min(res, dp[i - 1][j])
        i -= 1
        j += 1
    return res
  
# Driver Code
if __name__ == "__main__":
    inpt = "myfirstgeekarticle"
    print(getLevenstein(inpt))
  
# This code is contributed
# by vibhu4agarwal


C#
// C# program to find minimum deletions to make 
// palindrome.
using System;
  
class GFG 
{
    static int getLevenstein(String input)
    {
  
        // Find reverse of input string
        String revInput = Reverse(input);
  
        // Create a DP table for storing edit distance
        // of string and reverse.
        int n = input.Length;
        int[,] dp = new int[n + 1, n + 1];
        for (int i = 0; i <= n; ++i) 
        {
            dp[0, i] = i;
            dp[i, 0] = i;
        }
  
        // Find edit distance between input and revInput
        // considering only delete operation.
        for (int i = 1; i <= n; ++i) 
        {
            for (int j = 1; j <= n; ++j) 
            {
                if (input[i - 1] == revInput[j - 1])
                    dp[i, j] = dp[i - 1, j - 1];
                else
                    dp[i, j] = 1 + Math.Min(dp[i - 1, j], 
                                            dp[i, j - 1]);
            }
        }
  
        /* Go from bottom left to top right
        and find the minimum */
        int res = int.MaxValue;
        for (int i = n, j = 0; i >= 0; i--, j++) 
        {
            res = Math.Min(res, dp[i, j]);
            if (i < n)
                res = Math.Min(res, dp[i + 1, j]);
            if (i > 0)
                res = Math.Min(res, dp[i - 1, j]);
        }
        return res;
    }
    static String Reverse(String input)
    {
        char[] a = input.ToCharArray();
        int l, r = a.Length - 1;
        for (l = 0; l < r; l++, r--)
        {
            char temp = a[l];
            a[l] = a[r];
            a[r] = temp;
        }
        return String.Join("",a);
    }
      
    // Driver Code
    public static void Main(String[] args)
    {
        String input = "myfirstgeekarticle";
        Console.WriteLine(getLevenstein(input));
    }
}
  
// This code is contributed by 29AjayKumar


输出:

12

时间复杂度:O(  $n^{2}$ )
空间复杂度:O(  $n^{2}$ )
在哪里$n$是字符串的长度

为什么运作呢?
为了理解它,我们需要从创建dp [] []的一开始就开始,例如对于单词“ geek”,它最初看起来像这样:

   \begin{array}{c c c c c c} & null & g & e & e & k\\ null & 0 & 1 & 2 & 3 & 4\\ k & 1 & -1 & -1 & -1 & -1\\ e & 2 & -1 & -1 & -1 & -1\\ e & 3 & -1 & -1 & -1 & -1\\ g & 4 & -1 & -1 & -1 & -1\\ \end{array}

第一行和第一列都用数字1..4填充,因为这是创建空字符串所需的修改次数,即:
[0] [1] == 1,要从字母“ g”创建空字符串,请删除此字母
[0] [2] == 2,从字母“ ge”创建空字符串,删除这两个字母,依此类推。
第一栏的故事相同:
[1] [0] == 1,要从字母’k’中创建空字符串,请删除此一个字母
[2] [0] == 2,从字母“ ke”创建空字符串,删除这两个字母,依此类推。

现在,我们使用动态编程方法来获取最少的修改次数,以使其他所有子字符串成为第二个子字符串,最后dp [] []如下所示:

   \begin{array}{c c c c c c} & null & g & e & e & k\\ null & 0 & 1 & 2 & 3 & 4\\ k & 1 & 2 & 3 & 4 & 3\\ e & 2 & 3 & 2 & 3 & 4\\ e & 3 & 4 & 3 & 2 & 3\\ g & 4 & 3 & 4 & 3 & 4\\ \end{array}

因此,例如,从’kee’获得子字符串’gee’的最小修改次数为2。到目前为止,这种算法很好,但它可以完成两件事,即插入和删除字符,并且我们仅对删除次数感兴趣。因此,让我们再看一下结果数组,例如条目[4] [1],该条目指出:
[4] [1] –要从字符串“ keeg”中生成字符串“ g”,我们需要执行3次修改(即删除chars“ kee”)
[3] [2] –要从“ kee”中创建字符串“ ge”,我们还需要执行3种修改,即从第一个字符串“ g”和第二个“ ke”中删除
因此,基本上每次我们将沿对角线向上移动时,都会从左上角获得移除次数,以使相同的子字符串向后移动。这里要注意的是,这就像在字符串两个指针,一个指针从头开始移动,另一个指针从末尾移动。非常重要的一点是,字符串不必必须具有偶数个字符,因此这就是我们还必须检查dp [] []中的上限值和下限值的原因。