LeetCode 730. Count Different Palindromic Subsequences (区间DP)
题意
给一个字符串S,求它所有子序列中不同非空回文串的数量。字符串由 'a' 'b' 'c' 'd' 四个字母组成。
由于题目要求的是不同回文串。 abba 的回文串子序列为 a,b,aba,abba 其中 aba 只能算一次。
最近做 区间DP 的题,习惯起手写
for (int l = 0; l < n; l++) {
for (int s = 0; s + l < n; s++) {
int e = s + l;
.....
}
}
外层枚举区间长度,内层枚举区间起始位置。
设 dp[i][j] 表示 S[i...j] 子序列中包含的回文串的数量。
解法1、枚举回文串第一个字母
设回文串第一个字母是 a 则最后一个字母也要是 a 然后找到在区间 [s,t] 中第一个和最后一个 a 的位置 x 和 y ,则,首字母为 a 的回文串个数为 dp[x-1][y+1]
因为,如果使用的不是两边的 a 而是内部的 a 作为边界,能发现内部 a 做边界组成的回文串 两边的 a 做边界时都组成。
最后再用两边的 a 组成 aa 以及 单个 a。当范围内只存在一个 a 时,则能贡献的子串只有 1 个。
很难受的是直接递推超时了,递归才勉强能过。。。
class Solution {
public:
int countPalindromicSubsequences(string S) {
// dp[i][j] 表示 s[i...j] 包含的子序列个数
int n = S.size();
vector<vector<int>> pos(4, vector<int>());
vector<vector<int>> dp(n, vector<int>(n, 0));
for (int i = 0; i < n; i++) {
pos[S[i] - 'a'].push_back(i);
}
return dfs(S, pos, dp, 0, n - 1);
}
int dfs(string &S, vector<vector<int>> &pos, vector<vector<int>> &dp, int s, int t) {
if (s + 1 >= t) return t - s + 1;
if (dp[s][t]) return dp[s][t];
int ans = 0;
for (int i = 0; i < 4; i++) {
if (pos[i].empty()) continue;
auto first_pos = lower_bound(pos[i].begin(), pos[i].end(), s);
auto end_pos = upper_bound(pos[i].begin(), pos[i].end(), t) - 1;
if (first_pos == pos[i].end() || *first_pos > t) continue;
int f = *first_pos, e = *end_pos;
ans = (ans + 1) % 1000000007;
if (f != e) ans = (ans + 1) % 1000000007;
if (f + 1 < e) {
ans = (ans + dfs(S, pos, dp, f + 1, e - 1)) % 1000000007;
}
}
return dp[s][t] = ans;
}
};
求 S[s..e] 的回文串数
当 S[s] != S[e] 时,可得公式
dp[s][e] = dp[s+1][e] + dp[s][e-1] - dp[s+1][e-1];
即 (包含s + 两边都不含的) 和 (包含e+ 两边都不含的)- 两边都不含的
当 S[s] == S[e] 时 还用上面的公式会出现重复。
比如 aaa ,计算 dp[0][2] 时 ,dp[0][1] 包含 (aa) 和 dp[1][2] 包含的 aa 重复但是没有被减去。
而如果想要减去重复部分,就要找到和边界位置相同的字母。假设边界字母是 a,
当没有和边界位置相同的字母, dp[s][e] = dp[s+1][e-1](两边都不含的)+ dp[s+1][e-1](两边都不含的 + 两边的字母)+ 1 (两边的字母组成 aa) + 1 (单个首字母 a)
当存在和边界位置相同的字母,且只有一个,dp[s][e] = dp[s+1][e-1](两边都不含的)+ dp[s+1][e-1](两边都不含的 + 两边的字母)+ 1 (两边的字母组成 aa)
当存在和边界位置相同的字母,且有多个(2个及以上) 中间的组成的,可能会和中间的a加上边界之后重复,比如 a(aaa)a 中间组成a aa aaa 加上两边的a 就变成了 aaa aaaa aaaaa 那么 aaa就重复计算了,找到除了边界的两个a,最外层的两个a,设位置是 low 和 high 那么,dp[low+1][high-1] 中所有子序列和low high 组成的回文串与和s e 组成的回文串都会重复。所以要减去dp[low+1][high-1]。dp[s][e] = dp[s+1][e-1] * 2 - dp[low + 1][high - 1];
其实我也不是很懂。。。。瞎写的。。。真的好难啊。。。。
class Solution {
public:
int countPalindromicSubsequences(string S) {
int n = S.size();
int dp[n][n];
int mod = 1e9 + 7;
for (int l = 0; l < n; l++) {
for (int s = 0; s + l < n; s++) {
int e = s + l;
if (l <= 1) {
dp[s][e] = l + 1;
} else if (S[s] == S[e]) {
int low = s + 1, high = e - 1;
// 寻找最近的和 S[s](S[e]) 相同的字母的位置
while (low <= high && S[low] != S[e]) low++;
while (high >= low && S[high] != S[e]) high--;
if (low > high) dp[s][e] = dp[s+1][e-1] * 2 + 2;
else if (low == high) dp[s][e] = dp[s+1][e-1] * 2 + 1;
else dp[s][e] = dp[s+1][e-1] * 2 - (low + 1 < high ? dp[low + 1][high - 1] : 0);
} else {
dp[s][e] = dp[s+1][e] + dp[s][e-1] - dp[s+1][e-1];
}
dp[s][e] = (dp[s][e] % mod + mod) % mod;
}
}
return dp[0][n - 1];
}
};
LeetCode 730. Count Different Palindromic Subsequences (区间DP)的更多相关文章
- leetcode 730 Count Different Palindromic Subsequences
题目链接: https://leetcode.com/problems/count-different-palindromic-subsequences/description/ 730.Count ...
- LN : leetcode 730 Count Different Palindromic Subsequences
lc 730 Count Different Palindromic Subsequences 730 Count Different Palindromic Subsequences Given a ...
- [LeetCode] 730. Count Different Palindromic Subsequences 计数不同的回文子序列的个数
Given a string S, find the number of different non-empty palindromic subsequences in S, and return t ...
- 【LeetCode】730. Count Different Palindromic Subsequences 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 记忆化搜索 动态规划 日期 题目地址:https:/ ...
- 730. Count Different Palindromic Subsequences
Given a string S, find the number of different non-empty palindromic subsequences in S, and return t ...
- [LeetCode] Count Different Palindromic Subsequences 计数不同的回文子序列的个数
Given a string S, find the number of different non-empty palindromic subsequences in S, and return t ...
- [Swift]LeetCode730. 统计不同回文子字符串 | Count Different Palindromic Subsequences
Given a string S, find the number of different non-empty palindromic subsequences in S, and return t ...
- Count Different Palindromic Subsequences
Given a string S, find the number of different non-empty palindromic subsequences in S, and return t ...
- [LeetCode] 327. Count of Range Sum 区间和计数
Given an integer array nums, return the number of range sums that lie in [lower, upper] inclusive.Ra ...
- UVa11404 - Palindromic Subsequence(区间DP+打印路径)
题目大意 给定一个字符串,要求你删除尽量少的字符,使得原字符串变为最长回文串,并把回文串输出,如果答案有多种,则输出字典序最小的 题解 有两种解法,第一种是把字符串逆序,然后求两个字符串的LCS,并记 ...
随机推荐
- Dubbo日志链路追踪TraceId选型
一.目的 开发排查系统问题用得最多的手段就是查看系统日志,但是在分布式环境下使用日志定位问题还是比较麻烦,需要借助 全链路追踪ID 把上下文串联起来,本文主要分享基于 Spring Boot + Du ...
- Google主打的机器学习计算框架——jax的升级包
相关: 机器学习洞察 | 一文带你"讲透" JAX Jax的主要应用场景: 深度学习 (Deep Learning):JAX 在深度学习场景下应用很广泛,很多团队基于 JAX 开发 ...
- 【转载】 EdgeX Foundry试运行
原文地址: https://www.cnblogs.com/charlieroro/p/14843335.html ========================================== ...
- SSH如何通过proxy进行服务器连接
openssh是什么这里不做解释,但凡是用过linux系统的一般都是会了解这个的,毕竟openssh都是系统自带的应用. openssh一般都是指linux上的客户端,很多linux系统自有客户端的s ...
- 【分享】java精品实战教程
1.背景 大家好,我是一名地地道道的码农,平时在工作喜欢写博客, 一方面可以梳理技术点提升自己的技术,在遇到同样的问题时可以快速解决; 另一方面也想贡献自己的微博力量帮助其他遇到同样问题的人 后来觉得 ...
- DolphinScheduler 3.3.0版本更新一览
Apache DolphinScheduler即将迎来3.3.0版本的发布,届时将有一系列重要的更新和改进.在近期的社区5月份用户线上分享会上,项目PMC 阮文俊为大家介绍了3.3.0版本将带来的主要 ...
- 删除个文件夹,vfs2上传文件到ftp就异常553,这么不经事吗
开心一刻 今天逛街碰到街头采访,一上来就问我敏感话题 主持人:小哥哥,你单身吗 我:是啊 主持人:你找女朋友的话,是想找一个小奶猫呢,还是小野猫呢 我沉思了一下,叹气道:如果可以的话,我想找个人,而且 ...
- C#实现国产Linux视频录制生成mp4(附源码,银河麒麟、统信UOS)
随着信创国产化浪潮的来临,在国产操作系统上的应用开发的需求越来越多,最近有个客户需要在银河麒麟或统信UOS上实现录制摄像头视频和麦克风声音,将它们录制成一个mp4文件.那么这样的功能要如何实现了? 一 ...
- Web端OA办公后台管理系统(使用AxureRP设计)思路与效果分享
本期带来一套OA办公后台管理系统(办公一体化)的设计分享.本次的作品设计,使用AxureRP软件. 一套实用的后台OA系统,一定是功能强大.能覆盖常用功能的.本次分享的系统,包含组织.员工管理.考勤. ...
- JavaScript设计模式样例十一 —— 外观模式
外观模式(Facade Pattern) 定义:隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口. 目的:为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得 ...