当前位置 博文首页 > 数据结构和算法:LeetCode 647. 回文子串

    数据结构和算法:LeetCode 647. 回文子串

    作者:[db:作者] 时间:2021-07-29 12:44

    截止到目前我已经写了 500多道算法题,其中部分已经整理成了pdf文档,目前总共有1000多页(并且还会不断的增加),大家可以免费下载
    下载链接:https://pan.baidu.com/s/1hjwK0ZeRxYGB8lIkbKuQgQ
    提取码:6666

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    if (s.charAt(i) != s.charAt(j))
        continue;
    dp[i][j] = j - i <= 2 || dp[i + 1][j - 1];
    

    代码我们大致也能写出来了,因为是从i到j,所以j不能小于i。

        for (int i = 0; i < length; i--) {
            for (int j = i; j < length; j++) {
                if (s.charAt(i) != s.charAt(j))
                    continue;
                dp[i][j] = j - i <= 2 || dp[i + 1][j - 1];
            }
        }
    

    但是这里有个问题,如果我们想要求dp[i][j]还需要知道dp[i+1][j-1],如下图所示

    在这里插入图片描述
    对于这个二维数组,如果从上往下遍历当计算dp[i][j]的时候,我们还没有计算dp[i+1][j-1]的值,所以这个时候是没法计算dp[i][j]的,但我们可以从下往上计算,如下所示

        //从下往上计算
        for (int i = length - 1; i >= 0; i--) {
            for (int j = i; j < length; j++) {
                if (s.charAt(i) != s.charAt(j))
                    continue;
                dp[i][j] = j - i <= 2 || dp[i + 1][j - 1];
            }
        }
    

    我们来看下最终代码

    public int countSubstrings(String s) {
        int length = s.length();
        boolean[][] dp = new boolean[length][length];
        int count = 0;//回文串的数量
        //字符串从后往前判断
        for (int i = length - 1; i >= 0; i--) {
            for (int j = i; j < length; j++) {
                //如果i和j指向的字符不一样,那么dp[i][j]就
                //不能构成回文字符串
                if (s.charAt(i) != s.charAt(j))
                    continue;
                dp[i][j] = j - i <= 2 || dp[i + 1][j - 1];
                //如果从i到j能构成回文串,count就加1
                if (dp[i][j])
                    count++;
            }
        }
        return count;
    }
    

    在这里插入图片描述
    在这里插入图片描述

    public int countSubstrings(String s) {
        int length = s.length();
        boolean[][] dp = new boolean[length][length];
        int count = 0;//回文串的数量
        for (int j = 0; j < length; j++) {
            for (int i = 0; i <= j; i++) {
                //如果i和j指向的字符不一样,那么dp[i][j]就
                //不能构成回文字符串
                if (s.charAt(i) != s.charAt(j))
                    continue;
                dp[i][j] = j - i <= 2 || dp[i + 1][j - 1];
                //如果从i到j能构成回文串,count就加1
                if (dp[i][j])
                    count++;
            }
        }
        return count;
    }
    

    上面代码中dp是二维数组,但实际上在计算当前列的时候(如上图所示),我们只会用到上一列的结果,再往之前的就用不到了,所以我们还可以在优化一下,把二维数组改为一维。

    public int countSubstrings(String s) {
        int length = s.length();
        boolean[] dp = new boolean[length];
        int count = 0;//回文串的数量
        for (int j = 0; j < length; j++) {
            for (int i = 0; i <= j; i++) {
                if (s.charAt(i) == s.charAt(j) && (j - i <= 2 || dp[i + 1])) {
                    dp[i] = true;
                    count++;
                } else {
                    dp[i] = false;
                }
            }
        }
        return count;
    }
    

    在这里插入图片描述
    在这里插入图片描述
    视频链接

    在这里插入图片描述

    //回文串的数量
    int count = 0;
    
    public int countSubstrings(String s) {
        //边界条件判断
        if (s == null || s.length() == 0)
            return 0;
    
        for (int i = 0; i < s.length(); i++) {
            //回文的长度是奇数
            extendPalindrome(s, i, i);
            //回文是长度是偶数
            extendPalindrome(s, i, i + 1);
        }
        return count;
    }
    
    //以left和right为中心点,求回文字符串的数量
    private void extendPalindrome(String s, int left, int right) {
        while (left >= 0 && right < s.length() && s.charAt(left--) == s.charAt(right++)) {
            count++;
        }
    }
    

    在这里插入图片描述

    //中心点的个数
    public int countSubstrings(String s) {
        //字符串的长度
        int length = s.length();
        //中心点的个数
        int size = 2 * length - 1;
        //回文串的个数
        int count = 0;
        for (int i = 0; i < size; ++i) {
            //要么left等于right,要么left+1等于right。也就是说如果left等于
            //right,那么中心点就是一个字符,如果left+1等于right,中心点就是
            //2个字符
            int left = i / 2;
            int right = left + i % 2;
    
            while (left >= 0 && right < length && s.charAt(left--) == s.charAt(right++))
                ++count;
        }
        return count;
    }
    
    cs