题目来源
题目描述
class Solution {
public:
string longestPalindrome(string s) {
}
};
题目解析
区间型动态规划
(1)定义状态
dp[i][j]
表示字符串s
在[i, j]
区间的子串是否是一个回文串。
(2)推导状态转移方程
对于区间[i][j],有两种情况
- 如果 s [ i ] ! = s [ j ] s[i] != s[j] s[i]!=s[j],那么区间 [ i . . . j ] [i...j] [i...j]一定不是回文子串,即 d p [ i ] [ j ] = f a l s e dp[i][j] = false dp[i][j]=false
- 如果
s
[
i
]
=
=
s
[
j
]
s[i] == s[j]
s[i]==s[j],有下面三种情况:
- 情况一:下标
i
i
i和
j
j
j相同,同一个字符当然是回文子串,比如
a
- 情况二:下标
i
i
i和
j
j
j相差为1,也是回文子串,比如
aa
- 情况三:下标 i i i和 j j j大于1的时候,区间 [ i . . . j ] [i...j] [i...j]是不是回文子串取决于区间 [ i + 1... i − 1 ] [i+1...i-1] [i+1...i−1]。即 d p [ i ] [ j ] = = d p [ i − 1 ] [ j − 1 ] dp[i][j] == dp[i-1][j-1] dp[i][j]==dp[i−1][j−1]
- 情况一:下标
i
i
i和
j
j
j相同,同一个字符当然是回文子串,比如
- 要求最长回文子串,用遍历ans表示最长的回文子串,变量max_len 表示最长回文子串的长度
- 当 d p [ i ] [ j ] = t r u e dp[i][j] = true dp[i][j]=true时,当前回文子串的长度是curr_len = j - i
- 当curr_len> max_len 时,更新max_len和ans
(3)初始情况与边界情况
- d p [ i ] [ j ] dp[i][j] dp[i][j]初始化为false
(4)遍历顺序
- dp[i + 1][j - 1] 在 dp[i][j]的左下角
- 所以一定要从下到上,从左到右遍历,这样保证dp[i + 1][j - 1]都是经过计算的
class Solution {
public:
string longestPalindrome(string s) {
int len = s.size();
std::vector<std::vector<int>> dp(len, std::vector<int>(len, false));
std::string ans; int max_len = 0;
for(int i = len - 1; i >= 0; i--){
for (int j = i; j < len; ++j) {
if(s[i] == s[j]){
int curr_len = j - i;
if(curr_len <= 1 || dp[i + 1][j - 1]) {
dp[i][j] = true;
if(curr_len > max_len ){
max_len = curr_len;
ans = s.substr(i, curr_len + 1);
}
}
}
}
}
return ans;
}
};
枚举
枚举字符串 s 中的每一位,作为回文串的中心点,左右进行扩展,直到达到边界或者不满足回文串定义为止。
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:5. str中最长回文子串 Longest Palindromic Substring
- leetcode:647. 统计str中回文子串的个数 Palindromic Substrings
- leetcode:131. 切割str,使得每个子串均是回文,返回所有切割方案Palindrome Partitioning:
- leetcode:132. 分割str,使得每个子串均是回文,返回符合要求的最少切割次数 Palindrome Partitioning II :
- leetcode:214. 插入一些字符,令str成为回文串,返回最短回文串 Shortest Palindrome
- leetcode:1312. 插入一些字符,让str成为回文串。返回最少插入次数
- leetcode:409. 给定词频表,能够组成的最长回文串(不要求用光)
- leetcode:266. 给定词频表,能否组成回文串(必须用光) Palindrome Permutation
- leetcode:267. 给定词频表,组成回文串的所有方案(必须用光)
- leetcode:面试题 01.04. str是不是回文串的某个排列:消消乐
- leetcode:680. 删除一个/零个字符,str能否变成回文字符串:递归
- leetcode:1332. 要求删除仅由a和b的str,每次可以删除一个回文子序列,返回最小删除次数
- leetcode:336. 给定词频表,选2个单词拼接成回文串,返回所有的拼接方案 Palindrome Pairs
- leetcode:516. str中最长回文子序列的长度 Longest Palindromic Subsequence
- leetcode:730. 统计可以生成多少个不同回文子序列 Count Different Palindromic Subsequences
- leetcode:1143. str1和str2的最长公共子序列 Longest Common Subsequence
判断是不是回文
题目 | 思路 |
---|---|
leetcode:9. 判断整数num是不是回文数 Palindrome Number | 递归;反转全部的数(小心溢出);反转一半的数;转成字符串再判断; 双指针:取出最高位&最低位; |
leetcode:234. 判断链表是不是回文链表 Palindrome Linked List | 使用栈;反转整个链表比较;反转半个链表 |
leetcode:125. 验证字符串str是不是回文串 Validate Palindrome | 递归,双指针 |