数学题-6251. 统计回文子序列数目
1930. 长度为 3 的不同回文子序列
问题描述
给你一个字符串 s ,返回 s 中 长度为 3 的不同回文子序列 的个数。
即便存在多种方法来构建相同的子序列,但相同的子序列只计数一次。
回文 是正着读和反着读一样的字符串。
子序列 是由原字符串删除其中部分字符(也可以不删除)且不改变剩余字符之间相对顺序形成的一个新字符串。
例如,"ace" 是 "abcde" 的一个子序列。
示例 1:
输入:s = "aabca"
输出:3
解释:长度为 3 的 3 个回文子序列分别是:
- "aba" ("aabca" 的子序列)
- "aaa" ("aabca" 的子序列)
- "aca" ("aabca" 的子序列)
示例 2:
输入:s = "adc"
输出:0
解释:"adc" 不存在长度为 3 的回文子序列。
示例 3:
输入:s = "bbcbaba"
输出:4
解释:长度为 3 的 4 个回文子序列分别是:
- "bbb" ("bbcbaba" 的子序列)
- "bcb" ("bbcbaba" 的子序列)
- "bab" ("bbcbaba" 的子序列)
- "aba" ("bbcbaba" 的子序列)
提示:
3 <= s.length <= 105
s 仅由小写英文字母组成
问题求解
提前记录一下数字即可。
class Solution:
def countPalindromicSubsequence(self, s: str) -> int:
n = len(s)
res = 0
freq = Counter(s)
record = defaultdict(int)
used = set()
for i in range(n):
for c in freq.keys():
l = record[c]
r = freq[c] - record[c] if c != s[i] else freq[c] - record[c] - 1
if l and r and s[i] + c not in used:
used.add(s[i] + c)
res += 1
record[s[i]] += 1
return res
6251. 统计回文子序列数目
问题描述
给你数字字符串 s ,请你返回 s 中长度为 5 的 回文子序列 数目。由于答案可能很大,请你将答案对 109 + 7 取余 后返回。
提示:
如果一个字符串从前往后和从后往前读相同,那么它是 回文字符串 。
子序列是一个字符串中删除若干个字符后,不改变字符顺序,剩余字符构成的字符串。
示例 1:
输入:s = "103301"
输出:2
解释:
总共有 6 长度为 5 的子序列:"10330" ,"10331" ,"10301" ,"10301" ,"13301" ,"03301" 。
它们中有两个(都是 "10301")是回文的。
示例 2:
输入:s = "0000000"
输出:21
解释:所有 21 个长度为 5 的子序列都是 "00000" ,都是回文的。
示例 3:
输入:s = "9999900000"
输出:2
解释:仅有的两个回文子序列是 "99999" 和 "00000" 。
提示:
1 <= s.length <= 104
s 只包含数字字符。
问题求解
需要特别注意的是由于字符集的有限性,因此可以将两两配对的所有个数存储下来。
class Solution:
def countPalindromes(self, s: str) -> int:
suf = [0] * 10
suf2 = [0] * 100
for d in map(int, s[::-1]):
for i, c in enumerate(suf):
suf2[d * 10 + i] += c
suf[d] += 1
res = 0
pre = [0] * 10
pre2 = [0] * 100
for d in map(int, s):
suf[d] -= 1
for i, c in enumerate(suf):
suf2[d * 10 + i] -= c
res += sum(a * b for a, b in zip(suf2, pre2))
for i, c in enumerate(pre):
pre2[d * 10 + i] += c
pre[d] += 1
return res % (10 ** 9 + 7)