想了解更多数据结构以及算法题,可以关注微信公众号“数据结构和算法”,每天一题为你精彩解答。也可以扫描下面的二维码关注
给定字符串 s 和 t ,判断 s 是否为 t 的子序列。
示例 1:
s = “abc”, t = “ahbgdc”
返回 true.
示例 2:
s = “axc”, t = “ahbgdc”
返回 false.
双指针求解
这题让求的是s是否是t的子序列,我们可以使用两个指针,一个指向s的某个字符,一个指向t的某个字符,其中指向t的指针每次都会往右移一位,指向s的指针每次和指向t的指针所对应的字符相同时才会往右移,否则就不移动,当指向s的指针指向s的末尾的时候,返回true。这里以示例1为例来画个图看一下
原理很简单,我们来直接看下代码
public boolean isSubsequence(String s, String t) {
if (s.length() == 0)
return true;
int indexS = 0, indexT = 0;
while (indexT < t.length()) {
if (t.charAt(indexT) == s.charAt(indexS)) {
//指向s的指针只有在两个字符串相同时才会往右移
indexS++;
if (indexS == s.length())
return true;
}
//指向t的指针每次都会往右移一位
indexT++;
}
return false;
}
动态规划
我们用dp[i][j]表示字符串t的前j个字符包含s的前i个字符
所以递归公式是
1,s.charAt(i - 1) == t.charAt(j - 1)
dp[i][j] = dp[i - 1][j - 1]
2,s.charAt(i - 1) != t.charAt(j - 1)
dp[i][j] = dp[i][j - 1];
那么边界条件是什么呢,当s为空的时候,我们默认t是包含s的,所以当s为空的时候,返回true。有了递推公式和边界条件,代码就很容易写了,来看下
public boolean isSubsequence(String s, String t) {
if (s.length() == 0)
return true;
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 = 1; j <= t.length(); j++) {
//递推公式
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()];
}
逐个查找
如果熟悉java语言的都知道,在java中String类有这样一个方法
public int indexOf(int ch, int fromIndex)
他表示的是在字符串中是否存在一个字符ch,并且是从字符串的下标fromIndex开始查找的。我们要做的是在t字符串中查找s中的每一个字符,如果没查到,直接返回false。如果查到,就从t的下一个位置继续开始查
public boolean isSubsequence(String s, String t) {
int index = -1;
for (char c : s.toCharArray()) {
//index表示上一次查找的位置(第一次查找的时候为-1),
// 所以这里要从t的下标(index+1)开始查找
index = t.indexOf(c, index + 1);
//没找到,返回false
if (index == -1)
return false;
}
return true;
}
参照最长公共子序列
看到这道题我们还可以参照之前写的370,最长公共子串和子序列,我们只要求出s和t的最长公共子序列的长度即可,如果长度等于s的长度,说明s就是t的子序列
public boolean isSubsequence(String s, String t) {
int[] dp = new int[t.length() + 1];
int last = 0;
for (int i = 1; i <= s.length(); i++) {
for (int j = 1; j <= t.length(); j++) {
int temp = dp[j];
if (s.charAt(i - 1) == t.charAt(j - 1))
dp[j] = last + 1;
else
dp[j] = Math.max(dp[j], dp[j - 1]);
last = temp;
}
}
return dp[t.length()] == s.length();
}
总结
这题比较简单,但解法比较多,最容易想到的估计就是双指针了。