【leetcode】647 回文子串(动态规划,字符串)

题目链接:

题目描述

1 暴力

复杂度分析
时间复杂度:O(n^3)
空间复杂度:O(1)

class Solution {
public:
    int countSubstrings(string s) {
        if(s.empty()) return 0;
        int ret = 0;
        for(int i = 0; i<s.size(); ++i){
            for(int j = i; j<s.size(); ++j){
                if (isPalindrome(s,i,j))
                    ++ ret;
            }
        }
        return ret;
    }
    // 判断一个字符串是否为回文串
    bool isPalindrome(string s, int i, int j){
        while(i<=j){
            if(s[i++]!=s[j--])
                return false;
        }
        return true;
    }
};

在这里插入图片描述

2 从中心字符扩展

一个回文串的中心字符位置是固定的,可以用回文串的中心位置+长度来唯一表示一个回文串

以某一位字符串为中心,向两边扩展;
分别以奇数和偶数长度统计回文串数目

复杂度分析
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
public:
    int countSubstrings(string s) {
        if(s.empty()) return 0;
        int ret = 0;
        for(int i = 0; i<s.size(); ++i){
            count(s,i,i,ret);       // 以i位置字符为中心,长度为奇数的回文串数目
            count(s,i,i+1,ret);     // 以i,i+1位置字符为中心,长度为偶数的回文串数目
        }
        return ret;
    }

    void count(string &s, int begin, int end, int &ret){
        while (begin>=0 && end<s.size() && s[begin--] == s[end++])
            ++ ret;
    }
};

在这里插入图片描述

3 动态规划

二维数组dp[i][j]表示字符串s(i,j) 是否为回文串。
(1)首先需要初始化长度为1,2的字符串其dp值
(2)对于长度3~len

dp[i][j] = (s[i] == s[j] && dp[i+1][j-1])

需要注意的是,上式在遍历时不是从前往后遍历的,dp[i][j]依赖于dp[i+1][j-1]。所以坐标需要做处理,使得整个遍历过程是从前往后的。
因为前面已经求得了长度为1,2的字符串dp值,所以我们从i = 3~len开始遍历子串长度,并检查 j = 0~len-i+1为起点,end = j + i -1 为终点的子串是否为回文子串。

dp[j][end] = (s[j] == s[end] && dp[j+1][end-1])

复杂度分析
时间复杂度:O(n^2)
空间复杂度:O(n^2)

/*
 * 动态规划
 * 时间复杂度O(n^2) 空间复杂度O(n^2)
 */
class Solution {
public:
    int countSubstrings(string s) {
        if(s.empty()) return 0;
        int len = s.size();
        vector<vector<bool >> dp(len, vector<bool > (len, false));
        int ret = 0;

        // 首先处理长度为1和2的子串
        for (int i = 0; i < len; ++i) {
            dp[i][i] = true;            // 初始化长度为1的回文串
            ++ ret;
        }
        for (int i = 0; i< len -1; ++i){
            if (s[i] == s[i+1]){
                dp[i][i+1] = true;      // 初始化长度为2的回文串
                ++ ret;
            }
        }

        // i为遍历的子串长度,j为起始节点
        for (int i = 3; i <= len ; ++i) {
            for (int j = 0; j <= len -i + 1; ++j) {
                int end = j+i-1;
                if(s[j] == s[end] && dp[j+1][end-1]){
                    dp[j][end] = true;
                    ++ ret;
                }
            }
        }
        return ret;
    }
};

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/zjwreal/article/details/91492795