赞
踩
题目链接:Leetcode 647. 回文子串
题目描述: 给你一个字符串 s
,请你统计并返回这个字符串中回文子串的数目。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。
思路: 本题可以利用动态规划来解决。本题的关键逻辑是:判断s[i]
是否等于s[j]
。由于判断回文子串需要依次对比字符串的两侧字符,用一维数组不能很好的表示递推关系,因此需要利用二维数组。
dp[i][j]
:[i , j]
闭区间内的字符串是否为回文子串,是为true
;不是为false
s[i] != s[j]
,返回false
;如果s[i] == s[j]
,并且当i
与j
相差小于等于1的时候,一定是回文子串,返回true
,否则需要让i
和j
分别向内收缩一位(变成dp[i + 1][j - 1]
),重复上述判断。[i , i]
区间,都一定是回文子串,因此dp[i,i] = true
,其余均为false
i
需要从后向前,内层遍历j
需要从前向后。dp[i][j] == true
的个数代码如下:(dp)
class Solution { public: int countSubstrings(string s) { int n = s.size(); vector<vector<bool>> dp(n + 5, vector<bool>(n + 5, false)); int result = 0; for (int i = n - 1; i >= 0; i--)//注意遍历顺序 for (int j = i; j < n; j++) { if (s[i] == s[j] && (j - i <= 1 || dp[i + 1][j - 1])) { result++; dp[i][j] = true; } } return result; } };
既然断回文子串需要依次对比字符串的两侧字符,那我们也可以直接用双指针法来解决。为了使代码通俗易懂,我们可以将字符数为奇数的字符串和字符数为偶数的字符串分开计算。
代码如下:(双指针法)
class Solution { public: int countSubstrings(string s) { int n = s.size(); int result = 0; for(int i = 0; i < n; i ++ ) { result += extend(s, i, i);//奇数个字符的字符串 result += extend(s, i, i + 1); //偶数个字符的字符串 } return result; } int extend(const string& s,int i,int j)//判断[i,j]范围内是否是回文子串 { int res = 0; while(i >= 0 && j < s.size() && s[i] == s[j])//范围逐渐扩大 { i -- ; j ++ ; res ++ ; } return res; } };
题目链接:Leetcode 516.最长回文子序列
题目描述: 给你一个字符串 s
,找出其中最长的回文子序列,并返回该序列的长度。子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。
思路: 本题需要求回文子序列,也就是字符之间可以不连续,这样双指针法就不太容易实现了。不过本题还是可以利用动态规划来解决。本题的关键逻辑和上题相同:判断s[i]
是否等于s[j]
dp[i][j]
:字符串s
在[i, j]
范围内最长的回文子序列的长度s[i]
与s[j]
相同,那么dp[i][j] = dp[i + 1][j - 1] + 2
;如果s[i]
与s[j]
不相同,那么分别加入s[i]
和s[j]
看看哪一个可以组成最长的回文子序列:dp[i][j] = max(dp[i + 1][j], dp[i][j - 1])
dp[i][i] = 1
,其余均为0
dp[0][s.size()]
代码如下:(dp)
class Solution { public: int longestPalindromeSubseq(string s) { int n = s.size(); vector<vector<int>> dp(n + 5, vector<int>(n + 5, 0)); for(int i = 0; i < n; i ++ ) dp[i][i] = 1;//初始化 for(int i = n - 1; i >= 0; i -- ) for(int j = i + 1; j < n; j ++ ) { if(s[i] == s[j]) { dp[i][j] = dp[i + 1][j - 1] + 2; } else { dp[i][j] = max(dp[i + 1][j],dp[i][j - 1]); } } return dp[0][n - 1]; } };
总结: 尽管动态规划题目到这里已经结束,但是真正掌握dp
还远不如此,与君共勉!
最后,如果文章有错误,请在评论区或私信指出,让我们共同进步!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。