题目:就是给两个字符串s和t,来判断s是否是t的的子字符串,注意的是,作为子字符串或者说是子序列,可以不用必须是连贯的,可以中间隔几个,例如,"ace"
是"abcde"
的一个子序列,而"aec"
不是。
解题:
首先我啥也不管,来个笨法
还是双循环,但是有两个标记位,一个标记位count是来得到s字符串符合条件的和,(举个例子,s是asdfger,t是 sag,可以看出来这不是子字符串,只有s和g符合条件在t中找到对应的位置,所以count是2,不等于s的长度,所以不是子串)
一个标记位是记录匹配到对应的位置,下一次循环要从记录位置下一步去找,保证顺序。
来,代码展示
public boolean isSubsequence(String s, String t) {
char[] sArray = s.toCharArray();
char[] tArray = t.toCharArray();
int point = 0;
int count = 0;
for( char son : sArray ){
for(int i = point ; i< tArray.length ; i++ ){
if(son == tArray[i] ){
point = i + 1;
count += 1;
break;
}
}
}
if(count >= sArray.length){
return true;
}else {
return false;
}
}
第二,理解是好理解,但是代码长度有点长,如果不注意代码会出错(比如说忘记break,比如说 point位置没有加一,遇到重复的字符串就会出现问题)
所以还有一个双指针法,所谓的双指针法,算是贪心算法的一种,就是把所有的都找出来看看有没有符合条件的
所以双指针的退出条件就是,两个字符串长度是否遍历完。
public boolean isSubsequence(String s, String t) {
int n = s.length(), m = t.length();
int i = 0, j = 0;
while (i < n && j < m) {
if (s.charAt(i) == t.charAt(j)) {
i++;
}
j++;
}
return i == n;
}
遍历是遍历,咋样判断是否完全匹配呢,实际上还是要靠匹配的长度(跟我那个专门拿出一个记录总数不一样,他是直接循环,看短的字符串那一步执行不下去,然后再看这个长度是不是短字符串长度来判断)
时间复杂度我觉得应该是O(m+n),为什么不是O(m)那?最差情况每一步都要走,举个例子两个字符串是一样的,while是ture一直往下走,导致循环的每一步都符合不中断,一直走,最后是m+n
第三 动态规划DP
万物皆DP,也是没谁了,主要的操作就是先对数据预处理(对t或者说是父字符串),然后s过来匹配。
首先介绍一个比较不错的博客关于这个题目的动态规划题解
所谓的预处理就是把父字符串做个处理,画个表,第一步是这种
我们要开始填数字,填数字,注意填6的地方表示没用,或者是用不到,不好理解的话可以画X,我懒拿别人的图片就不多比比了。
填数字要注意是倒着填,ahbgdc,从c开始,而且每填完一个就上一个可以填的少一个
填完后类似这种
当然你会发现,t字符串还会出现重复的字符,这样的咋填,没事还是同样方法,只不过会覆盖上去,例如ahbgdb
然后结合官方解答方程和题解就能有一个大概的想法啦(最起码不会一脸问号,实际我也走到这一步稍微有点思路,也不能说完整的理解得很好,但是中间有很大一步都在预处理上了。)
官方动态规划
public boolean isSubsequence(String s, String 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;
for (int i = 0; i < n; i++) {
if (f[add][s.charAt(i) - 'a'] == m) {
return false;
}
add = f[add][s.charAt(i) - 'a'] + 1;
}
return true;
}