【LeetCode: 647. 回文子串 | 暴力递归=>记忆化搜索=>动态规划】

在这里插入图片描述

作者简介:硕风和炜,CSDN-Java领域新星创作者,保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文|经验分享|好用的网站工具分享
座右铭:人生如棋,我愿为卒,行动虽慢,可谁曾见我后退一步?

在这里插入图片描述

目录

    • 题目链接
    • 题目描述
    • 求解思路&实现代码&运行结果
      • 暴力递归
        • 求解思路
        • 实现代码
        • 运行结果
      • 记忆化搜索
        • 求解思路
        • 实现代码
        • 运行结果
      • 动态规划
        • 求解思路
        • 实现代码
        • 运行结果
    • 共勉

题目链接

647. 回文子串

题目描述

给你一个字符串 s ,请你统计并返回这个字符串中 回文子串 的数目。

回文字符串 是正着读和倒过来读一样的字符串。

子字符串 是字符串中的由连续字符组成的一个序列。

具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。

示例 1:
输入:s = “abc”
输出:3
解释:三个回文子串: “a”, “b”, “c”

示例 2:
输入:s = “aaa”
输出:6
解释:6个回文子串: “a”, “a”, “a”, “aa”, “aa”, “aaa”

提示:
1 <= s.length <= 1000
s 由小写英文字母组成

求解思路&实现代码&运行结果

暴力递归

求解思路

  1. 首先我们通过双层循环中的第一层循环来枚举左边界,第二层循环来枚举右边界,然后通过递归来找到当前字符串中回文串的个数,累加求得最终的结果。
  2. 求解中最重要的一环就是递归的设计,我们的递归怎么设计呢?

    1.我们递归是想求得当前子串中共有多少个回文子串,那么我们定义递归的含义就是从left开始,到right结束,递归的返回值表示共有多少个回文子串。
    2.递归的结束条件:如果left>=right,我们直接返回1。表示当前方案可行。
    3.递归的过程中如果当前俩个字符不想等,我们直接结束,否则继续判断。

实现代码

class Solution {
    public int countSubstrings(String s) {
        if(s.length()<=0||s==null) return 0;
        char[] arr=s.toCharArray();
        int ans=0;
        for(int i=0;i<arr.length;i++){
            for(int j=i;j<arr.length;j++){
                ans+=process(i,j,arr);
            }
        }
        return ans;
    }

    public int process(int left,int right,char[] arr){
        if(left>=right) return 1;
        if(arr[left]!=arr[right]) return 0;
        return process(left+1,right-1,arr);
    }
}

运行结果

【LeetCode: 647. 回文子串 | 暴力递归=>记忆化搜索=>动态规划】_第1张图片

记忆化搜索

求解思路

  1. 根据我们递归的分析,在递归的过程中会产生重复的子过程,所以我们想到了加一个缓存表,也就是我们的记忆化搜索。

实现代码

class Solution {
    public int countSubstrings(String s) {
        if(s.length()<=0||s==null) return 0;
        char[] arr=s.toCharArray();
        int[][] dp=new int[arr.length][arr.length];
        for(int i=0;i<arr.length;i++){
            Arrays.fill(dp[i],0);
        }
        int ans=0;
        for(int i=0;i<arr.length;i++){
            for(int j=i;j<arr.length;j++){
                ans+=process(i,j,arr,dp);
            }
        }
        return ans;
    }

    public int process(int left,int right,char[] arr,int[][] dp){
        if(dp[left][right]!=0) return dp[left][right];
        if(left>=right) return dp[left][right]=1;
        if(arr[left]!=arr[right]) return dp[left][right]=0;
        return dp[left][right]=process(left+1,right-1,arr,dp);
    }
}

运行结果

【LeetCode: 647. 回文子串 | 暴力递归=>记忆化搜索=>动态规划】_第2张图片

动态规划

求解思路

  1. 接下来我们根据之前的递归思路以及记忆化缓存改写动态规划。

实现代码

class Solution {
    public int countSubstrings(String s) {
        if(s.length()<=0||s==null) return 0;
        char[] arr=s.toCharArray();
        int[][] dp=new int[arr.length][arr.length];
        for(int i=0;i<dp.length;i++){
            for(int j=0;j<=i;j++){
                dp[i][j]=1;
            }
        }
        int ans=0;
        for(int i=arr.length-1;i>=0;i--){
            for(int j=i;j<arr.length;j++){
                if(i==j){
                    ans+=dp[i][j];
                }else if(i+1==j){
                    ans+=dp[i][j] = arr[i] == arr[j] ? 1 : 0;
                }else{
                    dp[i][j]=arr[i] == arr[j] ? dp[i+1][j-1] : 0; 
                    ans+=dp[i][j];  
                }
            }
        }
        return ans;
    }
}

运行结果

【LeetCode: 647. 回文子串 | 暴力递归=>记忆化搜索=>动态规划】_第3张图片

共勉

最后,我想送给大家一句一直激励我的座右铭,希望可以与大家共勉!

在这里插入图片描述

你可能感兴趣的:(#,动态规划系列,LeetCode每日一题打卡,leetcode,动态规划,java)