我需要找到将字符串转换为回文所需的最小插入次数。注意:插入可以发生在任何地方,结尾或内部。如果它只是在最后,我们有一个问题here。
所以我发现这可以通过这个简单的技巧在O(N**2)
时间内完成:
l
。x
。l-x
。例如,假设s1 = abcda
。因此s2 = adcba
。长度为5.最长公共子序列为长度为3的aba
。因此,最小插入次数为5-3 = 2
,这是实际答案,结果字符串为a
{ {1}} dc
。
然而,我无法理解它背后的逻辑。任何人都可以向我解释它为什么有效吗?
并且,有没有bcda
解决方案?
答案 0 :(得分:1)
我不知道是否有O(N)
解决方案,但通过与反向比较,您会找到一个回文序列。然后你有l-x
个没有配对的字母。 (如果你在镜子的中间有一面镜子,你可以考虑使用一个字母对作为它的反射。例如ab | ba)稍后,通过插入,你只需完成图片。
现在,首先,我们如何找到两个字符串共有的(最大)子序列?有一个多项式算法可以在这里找到它 https://en.wikipedia.org/wiki/Longest_common_subsequence_problem
当我们试图找到s1和s2之间最长的公共子序列(lcs)(s1的反向)时,我们实际上在s1的前半部分和上半部分s2之间找到lcs,也是s1的后半部分和s2的后半部分。 假设
s1 = abcddzac
所以s2 = cazddcba
。在这里,我们可以将其视为abcd
与cazd
(上半部分)的比较,再加上dzac
与dcba
(后半部分)的比较。我们可以看到两个比较都是相同的,除非它们相互反转,因此它们的连接必须是回文,所以l1和s2必须是回文。
一旦我们得到长度为4的lcs(ad|da
),我们就会有4个字母打破对称性(b,c,z,c)。然后我们为它们中的每一个插入一个字母以形成对称,即回文。我们将中间点设置为lcs的中间点,并考虑我们将s1从中间点分成两个,所以我们有
s1 = a
bc d|d
z a
c我们将它从d | d中分成两个,我们最终得到:
d
{Ž{1}}℃
a
{CB {1}}
现在我们只需在lcs的字母之间填充它们就可以了。在我们的案例中,步骤如下:
d
{Ž{1}}℃
a
{CB {1}}
d
{Ž{1}}℃
a
{ZCB {1}}
d
{ZC {1}}℃
a
{ZCB {1}}
d
{ZCB {1}}℃
a
{ZCB {1}}
d
{ZCB {1}}℃
a
{ZCB {1}}℃
现在我们从同一点开始它,我们有
c d
bcz a
zcb d
c这是一个回文。
注意:cddc也是一个ldc但不会改变步数。