最长回文子序列
给定一个字符串 s ,找到其中最长的回文子序列,并返回该序列的长度。可以假设 s 的最大长度为 1000 。
示例 1:
输入:
“bbbab”
输出:
4
一个可能的最长回文子序列为 “bbbb”。
解法:(参考)
与最长回文子串类似,都是从对角线往右上角更新。但是子序列可以不连续,所以递推公式是:
当子序列的首位相等时->dp[i][j] = dp[i+1][j-1] + 2;
当子序列的首位不同时->dp[i][j] = max(dp[i][j-1],dp[i+1][j]);
i为子序列的首部,j为子序列的尾部。
class Solution {
public:
int longestPalindromeSubseq(string s) {
if(s.empty())
return 0;
int len = s.size();
vector<vector<int>> dp(len,vector<int>(len,0));
for(int i=0;i<len;i++){
dp[i][i] = 1;
}
// l表示从i向后移动的位置也就是长度减一,i是起始坐标,j是结束位置坐标
for(int l=1;l<len;l++){
for(int i=0;l+i<len;i++){
int j = l+i;
if(s[i] == s[i+l]){
dp[i][j] = dp[i+1][j-1] + 2;
} else{
dp[i][j] = max(dp[i][j-1],dp[i+1][j]);
}
}
}
return dp[0][len-1];
}
};
每一轮循环得到一斜行,最终右上角的值就是最大值。
最大回文子串
Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.
Example 1:
Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.
Example 2:
Input: "cbbd"
Output: "bb"
solution:第一次还是先想到的是暴力法(没有通过时间的限制),后面又使用了动态规划,但是运行时间不是很理想,有待改进
动态规划步骤:
矩阵DP初始值都为0
首先是初始化(对角线NP[i][i]上都设置为1,以对角线上的元素为中心的回文长度都为奇数;有两辆相同的将对应的DP[i+1][i]
元素设置为1,以此两元素为中心的回文长度均为偶数)—>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ruuvgKCW-1600589113750)(https://github.com/githublss/image/blob/master/leetimage/first.png)]
然后是在初始化的基础上进行寻找—>
首先假设回文的长度为3,之后依次递增。如果中心的两侧的两个字符是相同的,将其规划进来,将DP中的对应位置设置为1,在进行的过程中用到了前面的结果,一定程度上提高了效率。
class Solution(object):
def longestPalindrome(self, s):
"""
:type s: str
:rtype: str
"""
# 暴力法,总是最先想到的
# def isRevrse(s):
# if(s==s[::-1]):
# return True
# else:
# return False
# maxlen = 0
# maxi = 0
# for i in range(len(s)):
# for j in range(len(s)-i+1):
# if(isRevrse(s[i:i+j]) & (j > maxlen)):
# maxlen = j
# maxi = i
# return s[maxi:maxi+maxlen]
### 动态规划一
dp=[[0 for i in range(len(s))] for j in range(len(s))]
maxLen = 1
left = 0
for i in range(len(s)): #初始化
dp[i][i]=1
left = i
for i in range(len(s)-1): #初始化
if s[i]==s[i+1]:
dp[i][i+1]=1
left = i
maxLen = 2
for l in range(3,len(s)+1,1): # l表示当前要检测的字串串的长度
for i in range(0,len(s)-l+1,1): # i表示当前要检测的字符串的起始位置
j = i + l -1 # j表示当前要检测的字符串的尾位置
if (dp[i+1][j-1]==1 and s[i]==s[j]):
dp[i][j] = 1
left = i
maxLen = l
return s[left:left+maxLen]
c++解法:
class Solution {
public:
string longestPalindrome(string s) {
if(s.empty())
return "";
int len = s.size();
vector<vector<int>> dp(len,vector<int>(len,0));
for(int i=0;i<len;i++){
dp[i][i] = 1;
}
int left = 0;
int maxLen = 1;
for(int i=0;i<len-1;i++){
if(s[i] == s[i+1]){
dp[i][i+1] = 1;
left = i;
maxLen = 2;
}
}
// 注意长度是小于等于len,i是子串的起始,j是子串的结尾。
for(int l=3;l<=len;l++){
for(int i=0;i<=len-l;i++){
int j = i+l-1;
if(s[i] == s[j] && dp[i+1][j-1] == 1){
dp[i][j] = 1;
left = i;
maxLen = l;
}
}
}
return s.substr(left,maxLen);
}
};