Tough time don't last, tough people do.
没有过不去的坎, 只有打不倒的人。
问题描述
给定字符串 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为例来画个图看一下
原理很简单,我们来直接看下代码
1public boolean isSubsequence(String s, String t) { 2 if (s.length() == 0) 3 return true; 4 int indexS = 0, indexT = 0; 5 while (indexT < t.length()) { 6 if (t.charAt(indexT) == s.charAt(indexS)) { 7 //指向s的指针只有在两个字符串相同时才会往右移 8 indexS++; 9 if (indexS == s.length())10 return true;11 }12 //指向t的指针每次都会往右移一位13 indexT++;14 }15 return false;16}
动态规划
我们用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。有了递推公式和边界条件,代码就很容易写了,来看下
1public boolean isSubsequence(String s, String t) { 2 if (s.length() == 0) 3 return true; 4 boolean[][] dp = new boolean[s.length() + 1][t.length() + 1]; 5 //边界条件 6 for (int i = 0; i < t.length(); i++) { 7 dp[0][i] = true; 8 } 9 for (int i = 1; i <= s.length(); i++) {10 for (int j = 1; j <= t.length(); j++) {11 //递推公式12 if (s.charAt(i - 1) == t.charAt(j - 1)) {13 dp[i][j] = dp[i - 1][j - 1];14 } else {15 dp[i][j] = dp[i][j - 1];16 }17 }18 }19 return dp[s.length()][t.length()];20}21
逐个查找
如果熟悉java语言的都知道,在java中String类有这样一个方法
public int indexOf(int ch, int fromIndex)
他表示的是在字符串中是否存在一个字符ch,并且是从字符串的下标fromIndex开始查找的。我们要做的是在t字符串中查找s中的每一个字符,如果没查到,直接返回false。如果查到,就从t的下一个位置继续开始查
1public boolean isSubsequence(String s, String t) { 2 int index = -1; 3 for (char c : s.toCharArray()) { 4 //index表示上一次查找的位置(第一次查找的时候为-1), 5 // 所以这里要从t的下标(index+1)开始查找 6 index = t.indexOf(c, index + 1); 7 //没找到,返回false 8 if (index == -1) 9 return false;10 }11 return true;12}
参照最长公共子序列
看到这道题我们还可以参照之前写的370,最长公共子串和子序列,我们只要求出s和t的最长公共子序列的长度即可,如果长度等于s的长度,说明s就是t的子序列
1public boolean isSubsequence(String s, String t) { 2 int[] dp = new int[t.length() + 1]; 3 int last = 0; 4 for (int i = 1; i <= s.length(); i++) { 5 for (int j = 1; j <= t.length(); j++) { 6 int temp = dp[j]; 7 if (s.charAt(i - 1) == t.charAt(j - 1)) 8 dp[j] = last + 1; 9 else10 dp[j] = Math.max(dp[j], dp[j - 1]);11 last = temp;12 }13 }14 return dp[t.length()] == s.length();15}
总结
这题比较简单,但解法比较多,最容易想到的估计就是双指针了。
长按上图,识别图中二维码之后即可关注。
如果喜欢这篇文章就点个"赞"吧