题解 | #将最长回文子串近似转化为最长公共子串问题#
最长回文子串
https://www.nowcoder.com/practice/b4525d1d84934cf280439aeecc36f4af
#include <vector> class Solution { public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param A string字符串 * @return int整型 */ int getLongestPalindrome(string A) { // write code here string A_rev = A; reverse(A.begin(), A.end()); int n = A.size(); //dp[i][j]表示以s1[i]和s2[j]结尾的字符串的公共最大长度 vector<vector<int>> dp(n, vector<int>(n, 0)); int res = 0; for(int i = 0; i < n; i++){ for(int j = 0; j < n; j++){ if(A[i]==A_rev[j]){ if(i==0 || j==0) dp[i][j] = 1; else dp[i][j] = dp[i-1][j-1]+1; } // 特殊判断是不是和自己匹配上了 if(dp[i][j] > res){ // j是A_rev中的匹配位置,befor_pos 表示了翻转前的位置 int before_pos = n-j-1; // 翻转前的位置+公共子串长度-1 应该等于当前匹配位置i,相等说明是可以更新答案的 if(before_pos+dp[i][j]-1 == i){ res = dp[i][j]; } } } } return res; } };
题目要求最长回文子串,从回文串的定义,不难理解回文串要满足正着读反着读都一样的要求。所以我想把初始字符串s翻转,得到s_rev,此时找s的最长回文子串问题就“基本”转化为了找到s和s_rev的最长公共子串问题。需要注意这两个问题是“基本”相等,但并不完全相等,下面会给出例子。
对于最长公共子串问题,可以定义二维数组dp,判断字符串1和字符串2对应的字符是否相等,不难写出转移方程为:
dp[i][j] = dp[i-1][j-1]+1,我们在遍历两个字符串的过程中,更新dp数组,记录dp数组中出现的最大值,最终将最大值作为答案输出。
但是在更新答案的过程中,有一种情况是不能更新答案的,如果s = “abc123cba”,s_rev=“abc321cba”,字符串s和s_rev的最大公共子串是“abc”,但你会发现他其实并不是一个回文串,这是不满足我们计算最长回文子串的初衷的。出现错误的原因是字符串s中的前三个字符“abc”和最后三个字符“cba”翻转后的“abc”匹配上了,这是我们不希望的,因此在更新答案的时候,需要特殊判断匹配成功的字符串是不是原来的字符串!!!(第一遍做就卡这里了) 判断的方法就是利用索引加加减减,判断是否符合条件即可。(见注释)