Java实现 LeetCode 115 不同的子序列
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 不同的子序列的更多相关文章
- 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 ...
- Leetcode 115.不同的子序列
不同的子序列 给定一个字符串 S 和一个字符串 T,计算在 S 的子序列中 T 出现的个数. 一个字符串的一个子序列是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串.(例 ...
- Java实现 LeetCode 152 乘积最大子序列
152. 乘积最大子序列 给定一个整数数组 nums ,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数). 示例 1: 输入: [2,3,-2,4] 输出: 6 解释: 子数组 [2,3] ...
- LeetCode 115.不同的子序列 详解
题目详情 给定一个字符串 S 和一个字符串 T,计算在 S 的子序列中 T 出现的个数. 一个字符串的一个子序列是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串.(例如, ...
- leetcode 115不同的子序列
滚动数组: /***** 下标从1开始 dp[i][j]:= numbers of subseq of S[1:j] equals T[1:i] if(s[j]==t[i]):(那么之后的子串可以是是 ...
- 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 ...
- 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. ...
- 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 ...
- 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 ...
随机推荐
- java项目部署Linux服务器几种启动方式总结经验
一:两种部署包: 部署之前先说下两种包,java项目部署到服务器一般有用war包的,也有用jar包的,微服务spring-cloud普及后大部分打包都是jar,部署之前先搞清楚自己要打war包还是ja ...
- angular 实现依赖注入
1:首先获取module对象var myAppModule = angular.module('myApp', []); 2:定义对象(类似spring中xml声明bean对象<bean id= ...
- 小姐姐教你定制一个Logstash Java Filter
Logstash是用来收集数据,解析处理数据,最终输出数据到存储组件的处理引擎.数据处理流程为: Logstash Java Filter 就是基于Logstash的Filter扩展API开发一个用J ...
- 力扣题解-面试题10- II. 青蛙跳台阶问题
题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶.求该青蛙跳上一个 n 级的台阶总共有多少种跳法. 答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008, ...
- Python的第三方web开发框架Django
1.Django Django是一个基于Python的第三方Web应用开发框架,可以简化Web开发. 官网:https://www.djangoproject.com/ 主要特点: ①采用MVC模型变 ...
- mysql小白系列_06 备份与恢复
1.使用mydumper工具全库备份. 1)源码编译安装 2)全库备份 2.误操作truncate table gyj_t1;利用mysqldump的备份和binlog日志对表gyj_t1做完全恢复. ...
- SpringBoot代码生成器,从此不用手撸代码
前言 通常在开始开发项目的时候,首先会建立好数据库相关表,然后根据表结构生成 Controller.Service.DAO.Model以及一些前端页面. 如果开发前没有强制的约束,而每个程序员都有自己 ...
- 201771010128王玉兰《面向对象程序设计(Java)第十四周学习总结》
第一部分:理论知识总结: (1)Swing 设计模式(Design pattern)是设计者一种流行的 思考设计问题的方法,是一套被反复使用,多数人 知晓的,经过分类编目的,代码设计经验的总结. 使用 ...
- 苏浪浪 201771010120 第四周 Java基本程序设计总结
第四章 对象与类 学习目标 掌握类与对象的基础概念,理解类与对象的关系: 掌握对象与对象变量的关系: 掌握预定义类的基本使用方法,熟悉Math类.String类.math类.Scanner类.Lo ...
- Havel定理 poj1659
http://blog.csdn.net/xcszbdnl/article/details/14174669 代码风格这里的 Frogs' Neighborhood Time Limit: 5000M ...