算法练习第四十九天 647|516

647 回文子串

思路:首先定义一个二维bool类型的dp数组,dp[i][j]表示s中从i到j这个子串是否是回文串。然后从后往前遍历s的每一个字符,同时从该字符开始向后遍历,判断是否是回文串,并将结果累加到结果result中。

如果s[i] == s[j],那么说明以s[i]和s[j]为首尾的子串可能是回文串,需要进一步判断。如果j-i<=1,说明该子串长度为1或2,肯定是回文串;如果dp[i+1][j-1]为true,说明该子串去掉首尾字符后仍为回文串,因此以s[i]和s[j]为首尾的子串是回文串,将dp[i][j]标记为true。

最终返回result即可,表示s中回文子串的数量。

1.动态规划

class Solution {
public:
    int countSubstrings(string s) {
        vector<vector<bool>> dp(s.size(), vector<bool> (s.size(), false));
        int result = 0;
        for(int i = s.size() - 1; i >= 0; i--){
            for(int j = i; j < s.size(); j++){
                if(s[i] == s[j] && (j - i <= 1 || dp[i + 1][j - 1])){
                    result++;
                    dp[i][j] = true;
                }
            }
        }
        return result;
    }
};

516.最长回文子序列

思路:首先定义一个二维int类型的dp数组,dp[i][j]表示s中从i到j这个子串的最长回文子序列长度。初始化dp数组的对角线上的元素,即dp[i][i] = 1,表示单个字符本身就是一个回文子序列。

然后从后往前遍历s的每一个字符,同时从该字符开始向后遍历。当s[i] == s[j]时,说明以s[i]和s[j]为首尾的子串可以构成回文子序列,所以dp[i][j] = dp[i+1][j-1] + 2;当s[i] != s[j]时,说明以s[i]和s[j]为首尾的子串无法构成回文子序列,需要从dp[i+1][j]和dp[i][j-1]中取最大值作为当前dp[i][j]的值。

最终返回dp[0][s.size()-1]即可,表示整个字符串s的最长回文子序列长度。

1.动态规划

class Solution {
public:
    int longestPalindromeSubseq(string s) {
        vector<vector<int>> dp(s.size(), vector<int> (s.size(), 0));
        for(int i = 0; i < s.size(); i++) dp[i][i] = 1;
        for(int i = s.size() - 1; i >= 0; i--){
            for(int j = i + 1; j < s.size(); 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][s.size() - 1];
    }
};
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容