题目
给定字符串 s 和 t ,判断 s 是否为 t 的子序列。
你可以认为 s 和 t 中仅包含英文小写字母。字符串 t 可能会很长(长度 ~= 500,000),而 s 是个短字符串(长度 <=100)。
字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。
示例1
输入:
s = “abc”, t = “ahbgdc”
输出:
true
示例2
输入:
s = “axc”, t = “ahbgdc”
输出:
false
后续挑战
如果有大量输入的 S,称作S1, S2, … , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码?
解法
双指针遍历比较简单
代码
#include <stdio.h>
#include <iostream>
#include <cstring>
using namespace std;
class Solution {
public:
bool isSubsequence(string s, string t) {
int len1 = s.length(),len2 = t.length();
int i=0,j=0;
while(j!=len2){
if(s[i]==t[j])
i++;
j++;
}
return i==len1;
}
};
int main()
{
string s1 = "axc";
string s2 = "ahbgdc";
Solution s;
cout<<s.isSubsequence(s1, s2);
return 0;
}
后续挑战:
动态规划
- 当字符串s的数量比较大的时候,需要一次次遍历字符串t
- 可以用f[i][j]表示从第i个下标开始(包括i),第一次出现字符j的下标是什么
- 状态转移方程:
- 如果在这个位置中的字符就是j,则f[i][j]=i
- 如果在这个位置中的字符不是j,j出现的位置还要往后f[i][j] = f[i+1][j]
- 需要从后往前遍历,因为前面的值需要依靠后面的来定
- 注意边界
f[t.length()][] = t.length() 做一个标记,从位置t.length-1的位置不存在任何字符
#include <stdio.h>
#include <iostream>
#include <cstring>
using namespace std;
class Solution {
public:
bool isSubsequence(string s, string t) {
int len1 = s.length(), len2 = t.length();
//初始化所有dp数组
vector<vector<int> > f(len2 + 1, vector<int>(26, 0));
for (int i = 0; i < 26; i++) {
f[len2][i] = len2;
}
// 对t倒着打表,对t只需要处理一次
for (int i = len2 - 1; i >= 0; i--) {
for (int j = 0; j < 26; j++) {
if (t[i] == j + 'a')
f[i][j] = i;
else
f[i][j] = f[i + 1][j];
}
}
int add = 0;
for (int i = 0; i < len1; i++) {//从下标add开始找到第一个字符是s[i]的下标,更新
if (f[add][s[i] - 'a'] == len2) {
return false;
}
add = f[add][s[i] - 'a'] + 1;/
}
return true;
}
};
int main()
{
string s1 = "axc";
string s2 = "ahbgdc";
Solution s;
cout<<s.isSubsequence(s1, s2);
return 0;
}
今天也是爱zz的一天哦!