给定字符串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( )
空间复杂度: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次修改(即删除chars“ kee”)
[3] [2] –要从“ kee”中创建字符串“ ge”,我们还需要执行3种修改,即从第一个字符串“ g”和第二个“ ke”中删除
因此,基本上每次我们将沿对角线向上移动时,都会从左上角获得移除次数,以使相同的子字符串向后移动。这里要注意的是,这就像在字符串两个指针,一个指针从头开始移动,另一个指针从末尾移动。非常重要的一点是,字符串不必必须具有偶数个字符,因此这就是我们还必须检查dp [] []中的上限值和下限值的原因。