题目
给定字符串 s 和 t ,判断 s 是否为 t 的子序列。
字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。
进阶:
如果有大量输入的 S,称作 S1, S2, … , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码?
示例 1:
输入:s = “abc”, t = “ahbgdc” 输出:true 示例 2:
示例 2:
输入:s = “axc”, t = “ahbgdc” 输出:false
提示:
0 <= s.length <= 100
0 <= t.length <= 10^4
两个字符串都只由小写字符组成。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/is-subsequence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
本题要我们求解一个字符串s是否是一个字符串t的子串。
我们可以很容易想到其中双指针的解法。
一、双指针
思路:
定义两个指针指向字符串s、t的头一个字符。将两个字符进行较。如果相同,两个的指针的向前进一位 ,如果不相同,将t的指针向前进一位。只到s或t的指针到头。
代码:
int m=t.length(),n=s.length();
int i=0,j=0;
while(i<m && j<n){
if(s.charAt(j)==s.charAt(i)){
j++;
}
i++;
}
return j==n;
二、动态规划
思路:
如上的代码,我们将大量的时间花在查找下一个与s中字符匹配的字符,我们可以预处理字符串t,以便于
我们可以快速的查找到下一个匹配的字符串。
具体:
使用一个二维数组 Temp[i][j] 存储预处理结果,改表达式表示 在字符串t中从i开始下一个j的位置。
(j:以a为0,表示26个字母)如果从i开始第一个j出现的位置为i(j的索引值为i,看前面i、j的含义),那么
Temp[i][j]=i;否则Temp[i][j]=temp[i+1][j];这样我们得到一个递推表达式
Temp[i][j]=i t[i]=j, Temp[i][j]=Temp[i+1][j] t[i]!=j;
预处理完成后,开始检测,我们从字符串s的第一个字符开始检测,我们设定一个数用来表示当前指针在t中的字符的位置。后面在代码中解释.
代码:
int n = s.length(), m = t.length();
int[][] f = new int[m + 1][26];
for (int i = 0; i < 26; i++) {
f[m][i] = m;
}
for (int i = m - 1; i >= 0; i--) {
for (int j = 0; j < 26; j++) {
if (t.charAt(i) == j + 'a')
f[i][j] = i;
else
f[i][j] = f[i + 1][j];
}
}
int add = 0; //add 表示
for (int i = 0; i < n; i++) { // i从 0到n-1 ,将s中的字符按顺序来检测一次
if (f[add][s.charAt(i) - 'a'] == m) {
return false; //代表从add开始后面没有 i(a~z :0~25)这个字母
}
add = f[add][s.charAt(i) - 'a'] + 1; //temp是预处理t的,add的值表示现在比较的起始位置,可以理解成我们我们已经提前找到下一个匹配字符的位置,完成匹配后,从当前重新开始匹配。(可以理解成 s是由t抽取出来的)
}
return true;