题目描述:
给定字符串 s 和 t ,判断 s 是否为 t 的子序列。字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。
进阶:
如果有大量输入的 S,称作 S1, S2, ... , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码?
链接:https://leetcode-cn.com/problems/is-subsequence
解法一及解析:
class solution{
public void isSubsequence(String s,String t){
/*
思路: 遍历t,与s的每一个字符进行对比,
如果匹配成功,则进行s下一个字符的匹配,
如果s所有的字符都进行了匹配,那么说明s是t的子序列
*/
int j=0;
for(int i=0;i
解析:
解法1思路简单,时间复杂度小O(n),空间复杂度O(1),如果单次检测性能高,但是如果有很多个s需要进行,每次都需要进行t遍历,那么效果会很低,从解法一中我们可以看出,性能优化点在遍历字符串t上,如果我们可以记录t中每个字符出现的下标,那么就可以跳过很多字符,不用每次都遍历t。
解法二及解析:
思路:预处理对于t的每一个位置,从当前下标往后每一个字符第一次出现的下标。用dp[i][j]来进行维护,dp[i][j]表示从当前下标i开始往后,字符j第一次出现的下标,状态转移:如果当前字符就等于j,那么dp[i][j]=i;如果当前字符不等于j,那么dp[i][j]=dp[i+1][j],即前一个下标开始,第一次出现的下标。
//状态转移方程
dp[i][j]=s.charAt(i)=='a'+j?i:dp[i+1][j];
完整代码:
class solution{
public void isSubsequence(String s,string t){
int m=s.length,n=t.length;
int[][] dp=new int[n+1][n+1];
//dp数组初始化,0~25代表a~z
for(int i=0;i<26;i++){
//初始化含义:从下标为n开始,所有的字符都不可达
dp[n][i]=n;
}
//记录String t中所有字符:
//注意,一定到倒序遍历,因为前面下标的dp值会用到后面下标的dp值
for(int i=n-1;i>=0;i--){
for(int j=0;j<26;j++){
dp[i][j]=t.charAt(i)=='a'+j?i:dp[i+1][j];
}
}
//开始检测String s
int cur=0;//记录在t中当前匹配的下标
for(int i=0;i