题目链接

https://leetcode-cn.com/problems/count-different-palindromic-subsequences/

题意

给定一个字符串,判断这个字符串中所有的回文子序列的个数。注意回文子序列不一定连续,可以删除某些字符得到。重复的回文字符串只计算一次。

思路:

动态规划,难点:

  1. 回文字符串怎么判重
  2. 动态规划的转移方程怎么推导

在这里我们假设dp[i][j]表示从[i,..,j]字符串中含有的不重复回文字符串的总数,那么首先来看边界条件:

如果每个字符串只有一个字符,显然dp[i][i]=1

如果含有多个字符,这时候我们根据这个字符串的首尾字符s[i],s[j]是否相同分类讨论:

  1. 如果s[i]!=s[j],那么dp[i][j]表示的总个数,显然可以由dp[i+1][j]+dp[i][j-1]-dp[i+1][j-1]转化而来,两者减去中间重复的值
  2. 如果s[i]==s[j],这时候就可能出现重复的情况:

    利用双指针的思想,设low=i+1,high=j-1

    while(low<=high && s[low]!=s[j]) low++;

    while(low<=high && s[high]!=s[j]) high--;

    找到左右两边分别第一个和s[i]相同的字符
  • 如果low>high,比如aba, 这时候dp[i][j]<--dp[i+1][j-1]*2+2 //*2的原因,可以看成dp[i+1][j-1],两端加或者不加s[i]的结果;+2的原因,可看成s[i],s[i]s[i]多于两种情况的结果
  • 如果low==high, 比如aaa,以此类推,dp[i][j]<--dp[i+1][j-1]*2+1; //有重复
  • 如果low<high,比如aabaa,以此类推, dp[i][i]<--dp[i+1][j-1]*2-dp[low+1][high-1];//中间b这一部分算了两遍
class Solution {
public:
//朴素解法: O(N^2*N)==>假算法,朴素解法应该是O(2^N)
//O(N^2)预处理所有情况,然后O(N^2)判断,用unordered_set统计 =>时间复杂度O(N^2)==>假算法,因为回文子序列并不一定连续。。。 //正解:区间dp, 状态转移方程真不好想
//难点:
//1. 如何去重
//如果推出dp[i][j]的转移方程,dp[i][j] 从[i,..,j]中不同回文字符串的个数,答案dp[0][n-1]
//三种情况,对应三种不同的例子:aaa, aba, aacaa const int Mod=1e9+7;
int countPalindromicSubsequences(string S){
int n=S.size();
vector<vector<int>> dp(n+1,vector<int>(n+1,0));
//单独一个字符
for(int i=0;i<n;i++) dp[i][i]=1;
for(int len=1;len<n;len++){
for(int i=0;i<n;i++){
int j=i+len;
if(j>=n) break; if(S[i]==S[j]){//最复杂的情况,需要判重
int low=i+1;
int high=j-1; while(low<=high && S[low] !=S[j]) low++;
while(low<=high && S[high] !=S[j]) high--;
//根据low和high的最终位置分类讨论
if(low>high) {//例子:aba
dp[i][j]=dp[i+1][j-1]*2+2;//两端相等 {b,aba,a,aa}
}
else if(low==high){//例子:aaa {a,aaa,aa}
dp[i][j]=dp[i+1][j-1]*2+1;
}
else{//例子:aabaa 有重复{b}这个位置重复了一次
//aba: {b,aba,a,aa}
//aabaa: {b,aba,a,aa; aba ,aabaa,aaa,aaaa, a,aa}
dp[i][j]=dp[i+1][j-1]*2-dp[low+1][high-1];
}
}
else{
//上一个状态[i,j]=[i,j-1]+[i+1,j]-[i+1,j-1]
dp[i][j]=dp[i+1][j]+dp[i][j-1]-dp[i+1][j-1];
} dp[i][j]=dp[i][j]<0?dp[i][j]+Mod:dp[i][j]%Mod;//防止溢出
}
}
return dp[0][n-1];
} // const int Mod=1e9+7;
// int countPalindromicSubsequences(string S) {
// int n=S.size();
// vector<vector<int>> dp(n,vector<int>(n,0));
// //处理长度为2时候对应的情况
// for(int i=0;i<n-1;i++){
// dp[i][i]=1;
// if(S[i]==S[i+1]) dp[i][i+1]=1;
// }
// dp[n-1][n-1]=1;
// //长度3以上的情况
// for(int len=3;len<n;len++){
// for(int i=0;i+len-1<n;i++){
// int j=i+len-1;
// if(S[i]==S[j] && dp[i+1][j-1]) dp[i][j]=1;
// }
// }
// //统计
// unordered_set<string> st;
// int ans=0;
// for(int i=0;i<n;i++){
// for(int len=1;len<n;len++){
// int j=i+len-1;
// if(j>=n) break;
// string tmp=S.substr(i,len);
// if(!st.count(tmp) && dp[i][j]){
// cout<<tmp<<"\n";
// ans=(ans+1)%Mod;
// st.insert(tmp);
// }
// }
// } // return ans;
// }
};

参考思路:

https://leetcode.com/problems/count-different-palindromic-subsequences/discuss/109507/Java-96ms-DP-Solution-with-Detailed-Explanation

leetcode 730. 统计不同回文子序列(区间dp,字符串)的更多相关文章

  1. Java实现 LeetCode 730 统计不同回文子字符串(动态规划)

    730. 统计不同回文子字符串 给定一个字符串 S,找出 S 中不同的非空回文子序列个数,并返回该数字与 10^9 + 7 的模. 通过从 S 中删除 0 个或多个字符来获得子字符序列. 如果一个字符 ...

  2. Leetcode 516.最长回文子序列

    最长回文子序列 给定一个字符串s,找到其中最长的回文子序列.可以假设s的最大长度为1000. 示例 1:输入: "bbbab" 输出: 4 一个可能的最长回文子序列为 " ...

  3. Java实现 LeetCode 516 最长回文子序列

    516. 最长回文子序列 给定一个字符串s,找到其中最长的回文子序列.可以假设s的最大长度为1000. 示例 1: 输入: "bbbab" 输出: 4 一个可能的最长回文子序列为 ...

  4. LeetCode 516——最长回文子序列

    1. 题目 2. 解答 与最长回文子串类似,我们可以用动态规划来求解这个问题,只不过这里的子序列可以不连续.我们定义状态 state[i][j] 表示子串 s[i, j] 的最长回文子序列长度,那么状 ...

  5. LeetCode.516 最长回文子序列 详解

    题目详情 给定一个字符串s,找到其中最长的回文子序列.可以假设s的最大长度为1000. 示例 1: 输入: "bbbab" 输出: 4 一个可能的最长回文子序列为 "bb ...

  6. poj3280 Cheapest Palindrome(回文串区间dp)

    https://vjudge.net/problem/POJ-3280 猛刷简单dp第一天第三题. 这个据说是[求字符串通过增减操作变成回文串的最小改动次数]的变体. 首先增减操作的实质是一样的,所以 ...

  7. nyoj 1023——还是回文——————【区间dp】

    还是回文 时间限制:2000 ms  |  内存限制:65535 KB 难度:3   描述 判断回文串很简单,把字符串变成回文串也不难.现在我们增加点难度,给出一串字符(全部是小写字母),添加或删除一 ...

  8. uva 10453 【回文串区间dp】

    Uva 10453 题意:给定字符串,问最少插入多少个字符使其变成回文串,并任意输出一种结果. 题解:和Uva 10739类似,这里是只能增加.类似定义dp[i][j]表示子串Si...Sj变为回文串 ...

  9. bzoj 1710: [Usaco2007 Open]Cheappal 廉价回文【区间dp】

    只要发现添加一个字符和删除一个字符是等价的,就是挺裸的区间dp了 因为在当前位置加上一个字符x就相当于在他的对称位置删掉字符x,所以只要考虑删除即可,删除费用是添加和删除取min 设f[i][j]为从 ...

随机推荐

  1. ssh远程服务器不通

    1.关闭防火墙 service iptables status service iptables stop 2.在/etc/hosts文件添加远程服务器信息(连接的两端都添加) 服务器1(racdb1 ...

  2. IDEA 2020.3 更新了,机器学习都整上了

    Hello,大家好,我是楼下小黑哥~ 上周 Java 开发申请神器 IDEA 2020.3 新版正式发布: 小黑哥第一时间就在开发机上更新了新版本,并且完整体验了两周了. 下面介绍一下这个版本的主要功 ...

  3. RocketMQ集群搭建(3m-3s-async)

    RocketMQ集群搭建(3m-3s-async) 各角色介绍 角色 作用 Producer 消息发送者,将消息发送到 Broker.无状态,其与NameServer集群中的一个节点建立长连接,定期从 ...

  4. [游记]FCS&FJOI2018滚粗记

    省冬连着省选,嗯这篇博客是省冬前就开的 省选是在情人节前一天- day0 中午早早的来了这边(找了个酒店到房间发现非常粉w 下午一个人去附中报到,然而-没有人带队签安全责任书好像不行-签到失败QAQ ...

  5. 关于_tostring[php]的另类利用

    收获 反序列化tostring的考点不一定要考察调用一个Class,也可以使用echo来进行考察 tostring()方法:在直接输出对象引用的时候,就不会产生错误,而是自动调用了__tostring ...

  6. 1.mysql表优化和避免索引失效原则

    表优化 1.单表优化 建立索引 根据sql的实际解析顺序建立复合索引 最佳左前缀,保持索引的定义和使用顺序一致 2.多表优化 连接查询 小表驱动大表:对于双层循环来说,外层循环(数据量)越小,内层循环 ...

  7. SQL优化器-RBO与CBO分别是什么

    数据库系统发展历史 数据库系统产生于20世纪60年代中期,至今有近50多年的历史,其发展经历了三代演变,造就了四位图灵奖得主,发展成为一门计算机基础学科,带动了一个巨大的软件产业. 数据库系统是操作系 ...

  8. Java中常见的json序列化类库 - Jackson

    Jackson 介绍 Jackson框架是基于Java平台的一套数据处理工具,被称为"最好的Java Json解析器". Jackson框架包含了3个核心库:streaming,d ...

  9. spring-boot 使用hibernate validation对参数进行优雅的校验

    springboot天生支持使用hibernate validation对参数的优雅校验,如果不使用它,只能对参数挨个进行如下方式的手工校验,不仅难看,使用起来还很不方便: if(StringUtil ...

  10. MySQL中的模糊查询 like 和 Oracle中的 instr() 函数有同样的查询效果

    注:MySQL中的模糊查询 like 和 Oracle中的 instr() 函数有同样的查询效果: 如下所示: MySQL: select * from tableName where name li ...