647. 回文子串
链接:代码随想录
动态规划解决的经典题目,如果没接触过的话,别硬想 直接看题解
做法一:暴力遍历
class Solution { //普通做法,暴力遍历,判断是否回文 public: int num=0; int countSubstrings(string s) { int n=s.size(); for(int i=0;i<n;i++) { is_huiwen(i,i,s,n); is_huiwen(i,i+1,s,n); } return num; } void is_huiwen(int left,int right,string &s,int n) { while(left>=0 && right<n &&s[left]==s[right]) { num++; left--; right++; } } };
动态规划做法,看了答案。
难点在于递推顺序,以及递推公式的构建和理解。
dp[i][j]相比前面的一些跟子序列、编辑距离相关的做法,取消了第0行第0列,dp[i][j]本身代表s[i...j]左闭右闭字符串是否为回文字符串。
以字符串"abdba"为例:
class Solution { /*动态规划,比较难以理解,建立在答案之上。 遍历顺序是从左下角开始的,也需要注意。 老实说,我感觉我理解了,能跟着老师思路顺下来,但是自己 想不到。 */ public: int countSubstrings(string s) { int n=s.size(); int cnt=0;//记录回文串个数 //定义 vector<vector<bool>>dp(n,vector<bool>(n,false)); //初始化 for(int i=0;i<n;i++) { dp[i][i]=true; } for(int i=n-1;i>=0;i--) { for(int j=i;j<n;j++) { if(s[i]!=s[j]) { dp[i][j]=false; } else { if(j-i<=1) { dp[i][j]=true; cnt++; } else { dp[i][j]=dp[i+1][j-1]; if(dp[i][j]==true) { cnt++; } } } } } //打印递推的数组 /*for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { cout<<dp[i][j]<<" "; } cout<<endl; }*/ return cnt; } };
516.最长回文子序列
647. 回文子串,求的是回文子串,而本题要求的是回文子序列, 大家要搞清楚两者之间的区别。
链接:代码随想录
答案这里没有想到。感觉理解的不是很透彻。
class Solution { /* 这个同时结合了最长公共子序列和回文子串的感觉!真神奇。 dp递推公式还是相当于没推理出来 */ public: int longestPalindromeSubseq(string s) { int n=s.size(); vector<vector<int>>dp(n,vector<int>(n,0)); for(int i=0;i<n;i++) { dp[i][i]=1; } for(int i=n-2;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]; } };
动态规划总结篇。留到周末看。