判断子序列

给定字符串 st ,判断 s 是否为 t 的子序列。

字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace""abcde"的一个子序列,而"aec"不是)。

  • 两个字符串都只由小写字符组成。

进阶:

如果有大量输入的 S,称作 S1, S2, … , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码?


方法一

用双指针非常容易想到

1
2
3
4
5
6
7
8
9
10
11
class Solution {
public:
bool isSubsequence(string s, string t) {
int i=0,j=0;
while(i<s.size()&&j<t.size()){
if(s[i]==t[j]) i++;
j++;
}
return i>=s.size()?true:false;
}
};

方法二

动态规划

f[i][j]表示在字符串t中,从位置i开始,j第一次出现的位置。

因为字符串只包括小写字母,所以j的范围是[0,25].

状态转移方程

1
2
3
4
f[i][j]={
i, t[i]-'a'==j
f[i+1][j], otherwise //所以i需要倒序遍历
}

初始化

1
for(int i=0;i<26;i++) f[len_t][i]=len_t;

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public:
bool isSubsequence(string s, string t) {
int len_s=s.size();
int len_t=t.size();
vector<vector<int>>f(len_t+1,vector<int>(26,0));
for(int i=0;i<26;i++)
f[len_t][i]=len_t;
for(int i=len_t-1;i>=0;i--){
for(int j=0;j<26;j++){
if(t[i]=='a'+j)
f[i][j]=i;
else
f[i][j]=f[i+1][j];
}
}
int add=0;
for(int i=0;i<len_s;i++){
if(f[add][s[i]-'a']==len_t)
return false;
else
add=f[add][s[i]-'a']+1;
}
return true;
}
};