问题描述
Given a string, your task is to count how many palindromic substrings in this string.
The substrings with different start indexes or end indexes are counted as different substrings even they consist of same characters.
Note:
- The input string length won't exceed 1000.
给定一个字符串,您的任务是计算该字符串中有多少回文子字符串。
具有不同起始索引或结束索引的子字符串被视为不同的子字符串,即使它们由相同的字符组成。
注意:
输入字符串长度不会超过1000。
例子 1:
输入: "abc"
输出: 3
解释: "a", "b", "c".
例子 2:
输入: "aaa"
输出: 6
解释: "a", "a", "a", "aa", "aa", "aaa".
Python 实现
回文串的特点是:正序或者逆序读取该字符串的结果是相同的。因此,我们只要找到每个子串相应的中间位置,分别向两端拓展,去判断两端的字符是否相同,从而可以逐个找出题目所要求的回文子串。
题目规定,即便两个子串由相同字符组成,只要他们具有不同的起始或者结束索引,则被视为不同的子字符串。因此,我们不需要再去区分不同位置的相同子字符串了。
实现一:从中间位置进行拓展
从中间索引开始拓展,主要分两种情况:子字符串长度为奇数,以及子字符串长度为偶数。
class Solution(object):
# Method 1.
def countSubstrings(self, s):
"""
:type s: str
:rtype: int
"""
cnt = 0
for i in range(len(s)):
# Odd length substrings.
cnt += self.checkFromMid(s, i, i)
# Even length substrings.
cnt += self.checkFromMid(s, i, i+1)
return cnt
def checkFromMid(self, s, left, right):
'''
Left and right are the middle indices as starts. Check a substring whether a palindromic string or not from its middle.
'''
cnt = 0
while left >= 0 and right < len(s) and s[left] == s[right]:
# Two edge's char is the same.
left -= 1
right += 1
cnt += 1
return cnt
实现二:动态规划
正如前面所说,寻找子字符串可以从中间开始,依次向两端拓展。所以,我们可以根据前面找到的回文子串为基础,再判断分别从两端拓展一个长度后的子串是否为回文串即可。这就是这一题动态规划的基本思路。
我们先列举总共可能出现的几种情况:
- 长度为1的子字符串:必然为回文串;
- 长度为2的子字符串:当两个字符都相同时,则为回文串;
- 长度大于3的子字符串:当其去掉头尾字符的子字符串为回文串,且头尾两个字符相同时,则为回文串。
以条件1、2作为基础条件,再根据条件3动态解出其他情况时的判断结果。
class Solution(object):
# Method 2: Dynamic Programming.
def countSubstrings(self, s):
"""
:type s: str
:rtype: int
"""
# Dynamic Programming.
'''
1. One-length substrings are always Palindromic Substrings.
2. Two-length substrings are always not Palindromic Substrings due to different characters at the start and the end.
3. Substrings whose lengths are over three are Palindromic Substrings only then their start and end characters are the same, and their substrings without the start and the end characters are still substrings.
Therefore, the first two conditions can be used as a basic step, and then generate the third situation with the previous two results.
'''
length = len(s)
# Input check.
if length == 0:
return 0
if length == 1:
return 1
# Create a len(s) by len(s) arrays to record the result of each substring by locating on the start and the end indices.
dp = [[False for j in range(length)] for i in range(length)]
cnt = 0
# ith row; jth col.
for i in range(length):
for j in range(i+1):
# One-length substring.
if i == j:
dp[i][j] = True
cnt += 1
# Two-length substring.
elif i == j+1 and s[i] == s[j]:
dp[i][j] = True
cnt += 1
# Inner substring is Palindromic Substring and the others characters are the same.
elif i > 0 and dp[i-1][j+1] and s[i] == s[j]:
dp[i][j] = True
cnt += 1
return cnt