给定一个字符串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( )
空间复杂度:O( )
在哪里是字符串的长度
为什么有效?
要理解它,我们需要从我们如何创建 dp[][] 开始,例如对于单词“geek”,它最初看起来像这样:
第一行和第一列都用数字 1..4 填充,因为这是创建空字符串所需的修改次数,即:
[0][1] == 1,从字母 ‘g’ 创建空字符串删除这一个字母
[0][2] == 2,从字母“ge”创建空字符串,删除这两个字母,等等。
第一列的相同故事:
[1][0] == 1,从字母 ‘k’ 创建空字符串删除这一个字母
[2][0] == 2,从字母“ke”创建空字符串,删除这两个字母,等等。
现在,我们使用动态规划方法来获得最少的修改次数,以使每个其他子字符串成为第二个子字符串,最后 dp[][] 看起来像这样:
例如,从 ‘kee’ 获取子字符串 ‘gee’ 的最小修改次数是 2。到目前为止还不错,但是这个算法做了两件事,插入和删除字符,我们只对删除次数感兴趣。因此,让我们再看看我们的结果数组,例如在条目 [4][1] 处,该条目指出:
[4][1] – 要从字符串“keeg”生成字符串“g”,我们需要执行 3 次修改(这只是删除字符“kee”)
[3][2] – 要从“kee”生成字符串“ge”,我们还需要通过从第一个字符串’g’ 和第二个 ‘ke’ 中删除来执行 3 次修改
所以基本上每次我们对角线向上移动时,从左角我们将获得移除次数以向后获得相同的子串。这里要注意的是,它就像在字符串两个指针,一个从头开始移动,另一个从尾端移动。非常重要的一点是字符串不必有偶数个字符,所以这就是我们还必须检查 dp[][] 中的上下值的原因。
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。