打印最长回文子串 (LPS)

huangapple go评论74阅读模式
英文:

Printing the Longest Palindromic Substring (LPS)

问题

我正在学习动态规划,我可以轻松解决最长回文子串的长度,但很难实际打印出最长的回文子串。我查看了一个视频链接,其中他展示了一种获取最长回文子串的方法,但我无法让它在较长的序列上正常工作。考虑来自geeksforgeeks的示例:

S: forgeeksskeegfor

现在,在我的方法中,我按以下顺序填充表的底部三角形:

for (int i = 1; i < dp.length; ++i)
    for (int j = i-1; j >= 0; --i)
        dp[i][j] = (s[i] == s[j]) ? 2+dp[i-1][j+1] : Math.max(dp[i][j+1], dp[i-1][j])

所以对于上面的字符串,我的DP表如下所示:

      0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
      f  o  r  g  e  e  k  s  s  k  e  e  g  f  o  r
 0 f  1
 1 o  1  1
 2 r  1  1  1
 3 g  1  1  1  1
 4 e  1  1  1  1  1
 5 e  2  2  2  2  2  1
 6 k  2  2  2  2  2  1  1
 7 s  2  2  2  2  2  1  1  1
 8 s  2  2  2  2  2  2  2  2  1
 9 k  4  4  4  4  4  4  4  2  1  1
10 e  6  6  6  6  6  6  4  2  1  1  1
11 e  8  8  8  8  8  6  4  2  2  2  2  1
12 g 10 10 10 10  8  6  4  2  2  2  2  1  1
13 f 12 10 10 10  8  6  4  2  2  2  2  1  1  1
14 o 12 12 10 10  8  6  4  2  2  2  2  1  1  1  1
15 r 12 12 12 10  8  6  4  2  2  2  2  1  1  1  1  1

这是来自视频的原始矩阵的转置,因此我不需要单独处理长度为1、2或大于等于3的回文子序列。无论我选择哪种方法,问题都是一样的。因此,最长回文子序列的长度在dp[15][0]处是12,这是正确的。问题出在回溯过程中...

12 => dp[15][0] => s[0] != s[15],现在我该怎么走... 在视频中,他选择了下一个或上面的元素中的最大值,但对于较长的字符串,这些值可能是相等的。所以,假设我向上走,'f'和'r'都不是LPS的一部分。
12 => dp[14][0] => s[0] != s[14]
12 => dp[13][0] => s[0] == s[13] => LPS: f[..........]f(在这一点上,我走对角线)
10 => dp[12][1] => s[1] != s[12] 在这一点上,我本来会像以前一样向上走,但如果我这样做,我就无法获得LPS,所以我必须向右走
10 => dp[12][2] => s[2] != s[12] 仍然向右走
10 => dp[12][3] => s[3] == s[12] => LPS: fg[........]gf
 8 => dp[11][4] => s[4] == s[11] => LPS: fge[......]efg
 6 => dp[10][5] => s[5] == s[10] => LPS: fgee[....]eefg
 4 => dp[ 9][6] => s[6] == s[ 9] => LPS: fgeek[..]keegf
 2 => dp[ 8][7] => s[7] == s[ 8] => LPS: fgeeksskeegf
 0 DONE

所以问题是,为什么我在找到dp[13][0]处的匹配后,从向上走改为向右走?如果我开始向右走,我找到了一个匹配,我无法继续向右走,也不能根据单元格的最大值来决定,因为它们可能相等。对于短字符串,当然可以,就像在链接的视频示例中一样,但仅限于此。对于相邻单元格相等的较长字符串,我应该选择哪个方向?

英文:

I'm learning DP for myself and I could solve the length of longest palindromic substring easily, but having a hard time to actually print the longest palindromic substring. I checked a video LINK where he shows a way to get the LPS but I can't get it to work for longer sequences. Consider the example from geeksforgeeks:

S: forgeeksskeegfor

Now in my approach I'm filling up the bottom triangle of the table like in the order of:

for (int i = 1; i &lt; dp.length; ++i)
    for (int j = i-1; j &gt;= 0; --i)
        dp[i][j] = (s[i] == s[j]) ? 2+dp[i-1][j+1] : Math.max(dp[i][j+1], dp[i-1][j])

So for the above string my DP table looks like:

      0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
      f  o  r  g  e  e  k  s  s  k  e  e  g  f  o  r
 0 f  1
 1 o  1  1
 2 r  1  1  1
 3 g  1  1  1  1
 4 e  1  1  1  1  1
 5 e  2  2  2  2  2  1
 6 k  2  2  2  2  2  1  1
 7 s  2  2  2  2  2  1  1  1
 8 s  2  2  2  2  2  2  2  2  1
 9 k  4  4  4  4  4  4  4  2  1  1
10 e  6  6  6  6  6  6  4  2  1  1  1
11 e  8  8  8  8  8  6  4  2  2  2  2  1
12 g 10 10 10 10  8  6  4  2  2  2  2  1  1
13 f 12 10 10 10  8  6  4  2  2  2  2  1  1  1
14 o 12 12 10 10  8  6  4  2  2  2  2  1  1  1  1
15 r 12 12 12 10  8  6  4  2  2  2  2  1  1  1  1  1

This is the transpose of the original matrix from the video an in turn I don't need to separately handle len 1,2,>=3 length of palindrom subsequences. The problem either way is the same whatever method I go for. So the length of the longest palindromic subsequence is at dp[15][0] := 12 which is correct. The problem is the tracing back...

12 =&gt; dp[15][0] =&gt; s[0] != s[15], now which way I go... I the video he goes on max of the next or top elements but for longer strings those might be equal. So, let&#39;s suppose I go upwards and nor &#39;f&#39; neither &#39;r&#39; are part of the LPS.
12 =&gt; dp[14][0] =&gt; s[0] != s[14]
12 =&gt; dp[13][0] =&gt; s[0] == s[13] =&gt; LPS: f[..........]f (At this point I go diagonally)
10 =&gt; dp[12][1] =&gt; s[1] != s[12] At this point I would start to go up as before but if I do that I won&#39;t get the LPS, so I have to go right
10 =&gt; dp[12][2] =&gt; s[2] != s[12] Still going right
10 =&gt; dp[12][3] =&gt; s[3] == s[12] =&gt; LPS: fg[........]gf
 8 =&gt; dp[11][4] =&gt; s[4] == s[11] =&gt; LPS: fge[......]efg
 6 =&gt; dp[10][5] =&gt; s[5] == s[10] =&gt; LPS: fgee[....]eefg
 4 =&gt; dp[ 9][6] =&gt; s[6] == s[ 9] =&gt; LPS: fgeek[..]keegf
 2 =&gt; dp[ 8][7] =&gt; s[7] == s[ 8] =&gt; LPS: fgeeksskeegf
 0 DONE

So the question is, why did I switch direction from going upwards to going right after I found a match at dp[13][0]? The same happens if I start going right I find I match I can't continue to go right nor can decide based on the max value of the cells as they might be equal. For short strings sure that works as in the example in the linked video but that's about it. Longer string equal adjacent cells then which way do I go?

答案1

得分: 0

为了在DP中进行回溯,你需要记住你是从哪里来的。一般来说,这意味着现在的内存将增加到O(N ^ 2),尽管你本可以用O(N)来完成它。

之所以从[12][1]跳到[12][2]而不是跳到[11][2],是因为如果你正在进行计算 - [12][1]的值将由[12][2]确定,因为这些字母不相等并且它是最大值。这就是为什么我们向右走的原因 - 它是决定这个单元格值的单元格。在所有其他情况下,这并不是那么重要,因为值相等,所以你可以向右或向上走。

英文:

In order to perform back tracing in DP you need to remember where you came from. Generally this means that The memory will now increase to O(N ^ 2) even though you could have done it in O(N).

The reason we go from [12][1] to [12][2] and not to [11][2] is that if you were doing the calculation - the value of [12][1] will be determined from [12][2] since the letters are not equal and it is the maximum. That is the reason we are going right - it was the cell that determined this cell value. In all the other cases it didn't really matter that much since the values were equal so you could go right or up.

huangapple
  • 本文由 发表于 2020年1月3日 19:07:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/59577508.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定