📌  相关文章
📜  生成字符串回文的最少删除次数 | 2套

📅  最后修改于: 2021-09-22 10:22:59             🧑  作者: 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


Javascript


输出:

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 次修改(这只是删除字符“kee”)
[3][2] – 要从“kee”生成字符串“ge”,我们还需要通过从第一个字符串’g’ 和第二个 ‘ke’ 中删除来执行 3 次修改
所以基本上每次我们对角线向上移动时,从左角我们将获得移除次数以向后获得相同的子串。这里要注意的是,它就像在字符串两个指针,一个从头开始移动,另一个从尾端移动。非常重要的一点是字符串不必有偶数个字符,所以这就是我们还必须检查 dp[][] 中的上下值的原因。

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程