//注意这种根据串长度来DP的思想,乍一看此题容易想到递推式,但如何实现,i,j的选取怎么定义,总不能胡乱选择i,j;
所以定义好边界条件,长度为1的全为回文串,然后按照长度从2->n依次自底向上规划,当然此题也可以设计成递归自顶向下,最好再加个备忘录。 #include <iostream> #include <string> #include <vector> using namespace std; class Solution { public: string longestPalindrome(string s) { int n = s.size(); if (n < 2) { return s; } int maxLen = 1; int begin = 0; // dp[i][j] 表示 s[i..j] 是否是回文串 vector<vector<int>> dp(n, vector<int>(n)); // 初始化:所有长度为 1 的子串都是回文串 for (int i = 0; i < n; i++) { dp[i][i] = true; } // 递推开始 // 先枚举子串长度 for (int L = 2; L <= n; L++) { // 枚举左边界,左边界的上限设置可以宽松一些 for (int i = 0; i < n; i++) { // 由 L 和 i 可以确定右边界,即 j - i + 1 = L 得 int j = L + i - 1; // 如果右边界越界,就可以退出当前循环 if (j >= n) { break; } if (s[i] != s[j]) { dp[i][j] = false; } else { if (j - i < 3) { dp[i][j] = true; } else { dp[i][j] = dp[i + 1][j - 1]; } } // 只要 dp[i][L] == true 成立,就表示子串 s[i..L] 是回文,此时记录回文长度和起始位置 if (dp[i][j] && j - i + 1 > maxLen) { maxLen = j - i + 1; begin = i; } } } return s.substr(begin, maxLen); } };
因为长度为1和长度为2的字符串其是否为回文串的状态容易确定,所以在确定了其状态后可以将其作为发散中心,向两边发散,得到发散的最远距离。
为何只用长度为1的解决不了呢,因为长度为1可能会受左右两个的影响如果他俩不一样的话,长度为2正好弥补了这种情况,当然长度为3以及更长也都可以转化为长度为1和2的情况
class Solution { public: pair<int, int> expandAroundCenter(const string& s, int left, int right) { while (left >= 0 && right < s.size() && s[left] == s[right]) { --left; ++right; } return {left + 1, right - 1}; } string longestPalindrome(string s) { int start = 0, end = 0; for (int i = 0; i < s.size(); ++i) { auto [left1, right1] = expandAroundCenter(s, i, i); auto [left2, right2] = expandAroundCenter(s, i, i + 1); if (right1 - left1 > end - start) { start = left1; end = right1; } if (right2 - left2 > end - start) { start = left2; end = right2; } } return s.substr(start, end - start + 1); } }; 作者:LeetCode-Solution 链接:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/zui-chang-hui-wen-zi-chuan-by-leetcode-solution/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
每天进步一点点~