115. 不同的子序列

给定一个字符串 S 和一个字符串 T,计算在 S 的子序列中 T 出现的个数。

一个字符串的一个子序列是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,“ACE” 是 “ABCDE” 的一个子序列,而 “AEC” 不是)

示例 1:

输入: S = “rabbbit”, T = “rabbit”

输出: 3

解释:

如下图所示, 有 3 种可以从 S 中得到 “rabbit” 的方案。

(上箭头符号 ^ 表示选取的字母)

rabbbit
^^^^ ^^
rabbbit
^^ ^^^^
rabbbit
^^^ ^^^

示例 2:

输入: S = “babgbag”, T = “bag”

输出: 5

解释:

如下图所示, 有 5 种可以从 S 中得到 “bag” 的方案。

(上箭头符号 ^ 表示选取的字母)

babgbag
^^ ^
babgbag
^^ ^
babgbag
^ ^^
babgbag
^ ^^
babgbag
^^^

PS:

还是佩服大佬们的面向测试用例编程

 /**
* 动态规划 但是效率并不高 20ms 35.83%
* 大部分都是二维动态规划 有的代码相同但是是5ms 估计是测试用例有变动
* 但是看到还是有节省的算法 所以一步一步往下优化
*
* * b a b g b a g
* * 1 1 1 1 1 1 1 1
* b 0 1 1 2 2 3 3 3
* a 0 0 1 1 1 1 4 4
* g 0 0 0 0 1 1 1 5
* @param s
* @param t
* @return
*/
public int numDistinct(String s, String t) {
int[][] dp = new int[t.length() + 1][s.length() + 1];
//初始化第一行
for(int j = 0; j <= s.length(); j++){
dp[0][j] = 1;
} for(int i = 1; i <= t.length(); i++){
for(int j = 1; j <= s.length(); j++){
if(t.charAt(i-1) == s.charAt(j-1)){
dp[i][j] = dp[i-1][j-1] + dp[i][j-1];
}else {
dp[i][j] = dp[i][j-1];
}
}
}
return dp[t.length()][s.length()];
} /**
* 二维换一维 严格按照二维的流程 参见上面矩阵 这个是15ms
* @param s
* @param t
* @return
*/
public int numDistinct2(String s, String t) {
int[] dp = new int[s.length() + 1];
Arrays.fill(dp, 1);
int pre = 1;
//每行算一次
for(int i = 0; i < t.length(); i++){
//0-n算n+1次
for(int j = 0; j <= s.length(); j++){
//先保存dp[j]下次用
int temp = dp[j];
if(j == 0){
dp[j] = 0;
}else {
if(t.charAt(i) == s.charAt(j-1)){
dp[j] = dp[j-1] + pre;
}else {
dp[j] = dp[j-1];
}
}
pre = temp;
}
}
return dp[s.length()];
} /**
* 列主序 倒序计算 就不用保存临时值pre了
* 可以按上图二维矩阵的顺序模仿一下 这个是11ms
* @param s
* @param t
* @return
*/
public int numDistinct3(String s, String t) {
// dp[0]表示空串
int[] dp = new int[t.length() + 1];
// dp[0]永远是1,因为不管S多长,都只能找到一个空串,与T相等
dp[0] = 1; for (int i = 0; i < s.length(); i++){
for (int j = t.length() - 1; j >= 0; j--) {
if (t.charAt(j) == s.charAt(i)) {
dp[j + 1] += dp[j];
}
}
}
return dp[t.length()];
} /**
* 列主序 先构造字典 就不用遍历t了
* 这样就优化成了答案上的2ms的了
* @param s
* @param t
* @return
*/
public int numDistinct4(String s, String t) {
// dp[0]表示空串
int[] dp = new int[t.length() + 1];
// dp[0]永远是1,因为不管S多长,都只能找到一个空串,与T相等
dp[0] = 1; //t的字典
int[] map = new int[128];
Arrays.fill(map, -1); //从尾部遍历的时候可以遍历 next类似链表 无重复值时为-1,
//有重复时例如从rabbit的b开始索引在map[b] = 2 next[2] 指向下一个b的索引为3
// for (int j = t.length() - 1; j >= 0; j--) {
// if (t.charAt(j) == s.charAt(i)) {
// dp[j + 1] += dp[j];
// }
// }
//这段代码的寻址就可以从map[s.charAt(i)] 找到索引j 在用next[j] 一直找和 s.charAt(i)相等的字符 其他的就可以跳过了
//所以这个代码的优化 关键要理解 上面的一维倒算
int[] nexts = new int[t.length()];
for(int i = 0 ; i < t.length(); i++){
int c = t.charAt(i);
nexts[i] = map[c];
map[c] = i;
} for (int i = 0; i < s.length(); i++){
char c = s.charAt(i);
for(int j = map[c]; j >= 0; j = nexts[j]){
dp[j + 1] += dp[j];
}
}
return dp[t.length()];
}

Java实现 LeetCode 115 不同的子序列的更多相关文章

  1. Java for LeetCode 115 Distinct Subsequences【HARD】

    Given a string S and a string T, count the number of distinct subsequences of T in S. A subsequence ...

  2. Leetcode 115.不同的子序列

    不同的子序列 给定一个字符串 S 和一个字符串 T,计算在 S 的子序列中 T 出现的个数. 一个字符串的一个子序列是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串.(例 ...

  3. Java实现 LeetCode 152 乘积最大子序列

    152. 乘积最大子序列 给定一个整数数组 nums ,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数). 示例 1: 输入: [2,3,-2,4] 输出: 6 解释: 子数组 [2,3] ...

  4. LeetCode 115.不同的子序列 详解

    题目详情 给定一个字符串 S 和一个字符串 T,计算在 S 的子序列中 T 出现的个数. 一个字符串的一个子序列是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串.(例如, ...

  5. leetcode 115不同的子序列

    滚动数组: /***** 下标从1开始 dp[i][j]:= numbers of subseq of S[1:j] equals T[1:i] if(s[j]==t[i]):(那么之后的子串可以是是 ...

  6. Java for LeetCode 216 Combination Sum III

    Find all possible combinations of k numbers that add up to a number n, given that only numbers from ...

  7. Java for LeetCode 214 Shortest Palindrome

    Given a string S, you are allowed to convert it to a palindrome by adding characters in front of it. ...

  8. Java for LeetCode 212 Word Search II

    Given a 2D board and a list of words from the dictionary, find all words in the board. Each word mus ...

  9. Java for LeetCode 211 Add and Search Word - Data structure design

    Design a data structure that supports the following two operations: void addWord(word)bool search(wo ...

随机推荐

  1. 译文:在GraalVM中部署运行Spring Boot应用

    GraalVM是一种高性能的多语言虚拟机,用于运行以JavaScript等基于LLVM的各种语言编写的应用程序.对于Java应用也可作为通常JVM的替代,它更具有性能优势.GraalVM带来的一个有趣 ...

  2. Handler Looper MessageQueue 之间的关系

    Handler Looper MessageQueue 之间的关系 handler在安卓开发中常用于更新界面ui,以及其他在主线程中的操作.内部结构大概图为: 1.handler持有一个Looper对 ...

  3. Spring全家桶之springMVC(四)

      路径变量PathVariable PathVariable   Controller除了可以接收表单提交的数据之外,还可以获取url中携带的变量,即路径变量,此时需要使用@PathVariable ...

  4. Android 开发技术周报 Issue#280

    新闻 6分钟完整视频提前看光谷歌新机Pixel 4a 统一推送官方解读:消灭Android毒瘤.待机续航猛增43% Google Play细化搜索结果:可按评分.编辑推荐.最新上线过滤 教程 了解一下 ...

  5. CleanWebpackPlugin最新版本使用问题

    如果在webpack 安装 CleanWebpackPlugin最新版本报错 如果是报下面的错误的话 然后在控制台向上翻 会发现 TypeError: CleanWebpackPlugin is no ...

  6. Vue Element-UI使用第三方icon图标(转)

    转载自:https://www.jianshu.com/p/59dd28f0b9c9 1.打开阿里icon,注册 >登录>图标管理>我的项目   2.新建项目 3. 添加icon到项 ...

  7. Django路由配置之子路由include(URL分发)

    子路由include(URL分发) 在一个项目中可能存在多个应用,为了方便区分和管理,在项目的总路由urls.py中会进行路由分发: (1)项目总路由导入from  django.conf.urls  ...

  8. FTP上传 -首先上传文件到的那台电脑得安装ftp

    /*↓↓↓↓ add upload ftp file 2014-03-16*/        /*↓↓↓↓ add 2014-03-16 ftp upload file*/    var $ftpse ...

  9. java中的上下问解释以及ServletContext介绍使用

    摘抄的:所谓上下文,它是用来存储系统的一些初始化信息,例如在jboss中通过配置文件指定了数据源,那么在jboss启动的时候就把这个文件的相关信息上下文中,于是在我们使用这个数据源的时候,就需要先获得 ...

  10. PAT-1056 Mice and Rice (分组决胜问题)

    1056. Mice and Rice Mice and Rice is the name of a programming contest in which each programmer must ...