题目
给定字符串 s 和 t ,判断 s 是否为 t 的子序列。
字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。
进阶:
如果有大量输入的 S,称作 S1, S2, … , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码?
示例 1:
输入:s = “abc”, t = “ahbgdc”
输出:true
示例 2:
输入:s = “axc”, t = “ahbgdc”
输出:false
提示:
- 0 <= s.length <= 100
- 0 <= t.length <= 10^4
- 两个字符串都只由小写字符组成。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/is-subsequence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
状态转移方程
if (s.charAt(i-1) == t.charAt(j-1)) {
dp[i][j] = dp[i-1][j-1];
} else {
dp[i][j] = dp[i][j-1];
}
dp[i][j] 表示S以第i-1个结尾,T以第j-1个结尾的情况下,S是否是T的字串。
因为最终是看S是否为T的子串,所以S必须以i结尾.
为了边界情况定义清晰,简单所以采用dp[s.length()+1][t.length()+1]。
这样i=0或者j等于0表示对应字符串是空串。
我这么说很难理解,可以自己写一下不减一的
Base
由状态转移方程可知
for (int i = 0; i < t.length(); i++) {
dp[0][i] = true;
}
答案
class Solution {
public boolean isSubsequence(String s, String t) {
if (s.length() == 0) {
return true;
}
if (t.length() == 0) {
return false;
}
boolean[][] dp = new boolean[s.length() + 1][t.length() + 1];
for (int i = 0; i < t.length(); i++) {
dp[0][i] = true;
}
for (int i = 1; i <= s.length(); i++) {
for (int j = i; j <= t.length(); j++) {
// i > j时表示字串长度大于父串一定为false,dp[][]数组默认为false,忽略
if (s.charAt(i-1) == t.charAt(j-1)) {
dp[i][j] = dp[i-1][j-1];
} else {
dp[i][j] = dp[i][j-1];
}
}
}
return dp[s.length()][t.length()];
}
}
其他解
一次遍历
遍历t,只要t依次包含s的所有字符串就表示s是t的子序列。用i表示t依次包含s的字符的个数,最后如果i==s.length()就返回true
class Solution {
public boolean isSubsequence(String s, String t) {
int i = 0;
int j = 0;
while (j < t.length()) {
// 由于循环没有关注i,s.charAt(i)可能越界,这里处理下边界
if (i == s.length()) {
return true;
}
if (s.charAt(i) == t.charAt(j)) {
i++;
}
j++;
}
return i == s.length();
}
}