leetcode647 回文子串

题目

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

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

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

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

示例

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

解析

首先这道题求的是回文串的数目,而不是一个字符串是不是回文串。
这道题还是用动归五部曲来分析下:
1.确定dp数组及其含义
对于大多数求子序列类的题目来说,求什么我们就定义什么,比如求回文子串的数目我们就定义成这个,但是对于这道题来说,dp[i] 和 dp[i-1] ,dp[i + 1] 看上去都没啥关系;
因此这道题,要定义dp[i][j]:表示区间范围[i,j] (注意是左闭右闭)的子串是否是回文子串,如果是dp[i][j]为true,否则为false。
注意初始化dp的时候,如果不管,默认就是false.
2.确定递推公式
还是先分为两步,如果s[i] != s[j],那什么都不用说了,肯定是dp[i][j] = false;(相当于不用处理)
如果相等,还需要再细分为以下三种情况:
一、下标 i == j,那么指向的是一个值,肯定是回文串
二、下标i - j = 1,因为此时的前提已经是s[i] == s[j]了,所以是类似与aa的,也是回文串(所以这两个条件可以合成一个)
三、下标差大于1,那么就看dp[i+1][j-1]是不是回文串
3.初始化
初始化当然是false
4.遍历顺序,求dp[i][j]的时候,子串是dp[i+1][j-1],相当于二维数组中的左下角位置,因此二维数组的遍历是从下到上,从左到右(这里的意思是,先要知道左下角的值,才能不断从左下角推导出右上角的位置)
在这里插入图片描述

func countSubstrings(s string) int {
    dp := make([][]bool, len(s) + 1)
    for i := range dp {
        dp[i] = make([]bool, len(s) + 1)
    }
    res := 0
    for i := len(s)-1; i >= 0; i-- {
        for j := i; j <= len(s)-1; j++ {
            if s[i] == s[j] {
                if j - i <= 1 || dp[i+1][j-1]{
                    dp[i][j] = true
                    res++
                }
            }
        } 
    }
    return res
}

注意里面遍历顺序那里,为什么内层循环需要j :=i呢,因为dp数组定义的是[i,j],所以j一定是大于i的;


上面的那种方法其实有点麻烦,还可以使用中心扩展法:
遍历s,以每个字母为中心扩散,判断是否为回文串
扩散时分两种情况:一个点为中心 或 两个点为中心

func countSubstrings(s string) int {
    n := len(s)
    result := 0
    for i := 0; i <= n-1; i++ {
        result += extend(s, i, i, n) // 一个点为中心
        result += extend(s, i, i+1, n) // 两个点为中心
    }
    return result
}
func extend(s string, i,j,n int) int{
    res := 0
    for i >= 0 && j < n && s[i] == s[j] {
        i-- //因为要中心扩展,所以符合条件的要在此基础上,分别向左右扩展,所以i是--,j是++,和别的是相反的
        j++
        res++
    }
    return res
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值