Given a string s and a string t, check if s is subsequence of t.

You may assume that there is only lower case English letters in both s and t. t is potentially a very long (length ~= 500,000) string, and sis a short string (<=100).

A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, "ace" is a subsequence of "abcde" while "aec" is not).

Example 1:

s = "abc", t = "ahbgdc"

Return true.

Example 2:

s = "axc", t = "ahbgdc"

Return false.

Follow up:
If there are lots of incoming S, say S1, S2, ... , Sk where k >= 1B, and you want to check one by one to see if T has its subsequence. In this scenario, how would you change your code?


 

解法一(贪心算法):其实有点像字符串匹配的问题。如果维持两个指针分别指向两个字符串起点并开始遍历,找到匹配就移动两个指针向后,找到不匹配只移动待搜索的字符串的指针以寻找下一个匹配点。最后判断时候目标字符串已被遍历完成即可。思路很简单,而且是有一种“贪心”的想法在里面,即遇到匹配的就加入。

 

解法二(动态规划):看到follow up和标签,想想其他的办法。首先动态规划是一定可以做的。假设boolean dp[i][j]表示s从0到i位置的字符串是否是t从0到j位置字符串的子串。那么当s[i]和t[j]相等的时候,只需要判断s(0, i-1)是不是t(0, j-1)的子串;如果s[i]和t[j]不相等,那么要一直往前看s(0, i)是不是t(0, j-1)的子串。只要注意边界情况就好。如果j是0,即t只有一个字符的时候都还没有能和s匹配,那么一定是不匹配。而且如果i>j,那么dp[i][j]一定是false,因为短字符串没法匹配长字符串。把递推公式实现,就是动态规划的解法。虽然运行速度很慢,但还是能过,显然这个方法是被允许的。

 

解法三(二分查找):最后想一下,如果输入是大量的s需要进匹配那要怎么做。s可以有很多,但t只有一个。如果把t里面每个字符出现时的索引存起来,这样遇到一个s,那就看首先s中的字符在t中有没有出现(即存储那个索引的结构是不是空),没有出现直接返回false。如果出现了,那么记下它在t中出现的位置,比如设为preIndex,之后搜索s中下一个字符。这时候如果字符仍然在t中存在,那其实应该寻找第一个大于preIndex的位置(即寻找第一个大于等于preIndex+1的索引)才可以实现匹配。在有序结构里寻找特定数,就是标签中有二分查找的由来。

 


解法一(Java)

public class Solution {
    public boolean isSubsequence(String s, String t) {
        int i = 0, j = 0;
        while(i < s.length() && j < t.length()) {
            if(s.charAt(i) == t.charAt(j)) i++;
            j++;
        }
        if(i == s.length()) return true;
        return false;
    }
}

 

解法二(Java)

public class Solution {
    public boolean isSubsequence(String s, String t) {
        int m = s.length(), n = t.length();
        if (m == 0) return true;
        if (n == 0) return false;
        boolean[][] dp = new boolean[m][n];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (i > j) dp[i][j] = false;
                else if (s.charAt(i) == t.charAt(j)) {
                    if (i == 0 || j == 0) dp[i][j] = i <= j ? true : false;
                    else           dp[i][j] = dp[i-1][j-1];
                } 
                else dp[i][j] = j == 0 ? false : dp[i][j-1];
            }
        }    
        return dp[m-1][n-1];
    }   
}

 

解法三(Java)

public class solution {
    public boolean isSubsequence(String s, String t) {
        int m = s.length(), n = t.length();
        if (m == 0) return true;
        if (n == 0) return false;
        List<Integer>[] list = new List[256];
        for (int i = 0; i < n; i++) {
            char c = t.charAt(i);
            if (list[c] == null) list[c] = new ArrayList<Integer>();
            list[c].add(i);
        }
        int preIndex = -1;
        for (int i = 0; i < m; i++) {
            char c = s.charAt(i);
            if (list[c] == null) return false;
            int index = binarySearch(list[c], preIndex + 1);
            if (index == -1) return false;
            else preIndex = index;
        }
        return true;
}
public int binarySearch(List<Integer> list, int key) { int lo = 0, hi = list.size() - 1; while (lo < hi) { int mid = lo + (hi - lo) / 2; if (key > list.get(mid)) lo = mid + 1; else hi = mid; } if (list.get(hi) < key) return -1; return list.get(hi);
} }

 

posted on 2018-06-29 14:37  小T在学习  阅读(506)  评论(0编辑  收藏  举报