力扣 647.回文子串

动态规划解法 (c语言)

对于字符s[i],如果s[i-1]与s[i+1]相等则从i-1到i+1三个字符构成回文字符

由此定义一个二维数组dp,数组初始化为0,对于dp[i][j](j >= i),值为1表示区间[i,j](左闭右闭)的子串构成回文子串,值为0则不构成回文子串。

如果s[i]和s[j]不相等则dp[i][j]一定等于0,如果s[i]与s[j]相等则要考虑以下三种情况

1. i == j,dp[i][j] = 1, 如 "a";

2. i 与 j 相邻 即 j - i == 1,dp[i][j] = 1, 如"aa";

3. j - i > 1, dp[i][j]的值取决于dp[i+1][j-1]。如"faf"、"fabf";

dp[i+1][j-1]位于dp[i][j]的左下方,因此采用自下而上、自左向右的方法遍历dp,又因为 j >= i 所以只会遍历到ap数组的右上半部分,具体代码如下

int countSubstrings(char * s){
    int ans = 0;
 
    int n = strlen(s);
    int **dp = (int **)malloc(sizeof(int *) * n);
    for(int i = 0; i < n; ++i){
        dp[i] = (int *)malloc(sizeof(int) * n);
        // memset(dp[i], 0, sizeof(dp[i]));
    }

    //初始化
    for(int i = 0; i < n; ++i){
        for(int j = 0; j < n; ++j)
            dp[i][j] = 0;
    }

    // n = n-1;
    //j一定大于等于i
    for(int i = n - 1; i >= 0; --i){
        for(int j = i; j < n; ++j){
            if(s[j] == s[i])
                if((j-i) <= 1){//同一个字符或者相邻两个字符
                    ++ans;
                    dp[i][j] = 1;
                    printf("%d %d\n", i,j);
                }else if(dp[i+1][j-1]){
                    ++ans;
                    dp[i][j] = 1;
                    printf("%d %d\n", i,j);
                }
        }
    }

    return ans;
}

你可能感兴趣的:(动态规划,leetcode,算法,c语言,c++)