Given string S and a dictionary of words words, find the number of words[i] that is a subsequence of S. Example : Input: S = "abcde" words = ["a", "bb", "acd", "ace"] Output: 3 Explanation: There are three words in words that are a subsequence of S: "a", "acd", "ace". https://leetcode.com/problems/number-of-matching-subsequences/solution/ Solution 1 : passed 80% cases but TLE on some extremely long strings // the total time complexity is the number of words * the length of S + the sum of the words[i].length // space : 1 class Solution { public int numMatchingSubseq(String S, String[] words) { int res = 0; for(String word : words){ // # of words if(isSubSeq(word, S)) res++; } return res; } private boolean isSubSeq(String word, String S){ int i = 0; for(char c : S.toCharArray()){ // the length of S if(i < word.length() && c == word.charAt(i)) i++; // i < word.length() // for each word, it's words[i].length } return i == word.length(); } } // use tree set class Solution { HashMap<Character, TreeSet<Integer>> map; public int numMatchingSubseq(String S, String[] words) { map = new HashMap<>(); for(int i = 0; i < S.length(); i++){ TreeSet<Integer> set = map.get(S.charAt(i)); if(set == null){ set = new TreeSet<>(); map.put(S.charAt(i), set); } set.add(i); } int res = 0; for(String word : words){ // # of words if(isSubSeq(word, S)) res++; } return res; } private boolean isSubSeq(String s, String t) { int prev = -1; for(int i = 0; i < s.length(); i++){ char c = s.charAt(i); TreeSet<Integer> set = map.get(c); if(set == null) return false; if(prev == -1){ prev = set.first(); }else{ Integer tmp = set.higher(prev); if(tmp == null) return false; prev = tmp; } } return true; } } Solution 2 : one pass Runtime is linear in the total size of the input (S and all of words). // time : is linear to the sum of word[i].length() + s.length() // space : sum of word[i].length() class Solution{ public int numMatchingSubseq(String S, String[] words){ int res = 0; ArrayList<Node>[] array = new ArrayList[26]; // new ArrayList[] for(int i = 0; i < 26; i++){ array[i] = new ArrayList<Node>(); } for(String word : words){ // the sum of word.length() array[word.charAt(0) - 'a'].add(new Node(word, 0)); } for(char c : S.toCharArray()){ // s.length() ArrayList<Node> bucket = array[c - 'a']; array[c - 'a'] = new ArrayList<Node>(); for(Node node : bucket){ node.index++; if(node.index == node.word.length()){ res++; }else{ array[node.word.charAt(node.index) - 'a'].add(node); } } bucket.clear(); // The java.util.ArrayList.clear() method removes all of the elements from this list.The list will be empty after this call returns. } return res; } } class Node{ String word; int index; public Node(String w, int i){ word = w; index = i; } } Explanation: I go through S once, and while I'm doing that, I move through all words accordingly. That is, I keep track of how much of each word I've already seen, and with each letter of S, I advance the words waiting for that letter. To quickly find the words waiting for a certain letter, I store each word (and its progress) in a list of words waiting for that letter. Then for each of the lucky words whose current letter just occurred in S, I update their progress and store them in the list for their next letter. Let's go through the given example: S = "abcde" words = ["a", "bb", "acd", "ace"] I store that "a", "acd" and "ace" are waiting for an 'a' and "bb" is waiting for a 'b' (using parentheses to show how far I am in each word): 'a': ["(a)", "(a)cd", "(a)ce"] 'b': ["(b)b"] Then I go through S. First I see 'a', so I take the list of words waiting for 'a' and store them as waiting under their next letter: 'b': ["(b)b"] 'c': ["a(c)d", "a(c)e"] None: ["a"] You see "a" is already waiting for nothing anymore, while "acd" and "ace" are now waiting for 'c'. Next I see 'b' and update accordingly: 'b': ["b(b)"] 'c': ["a(c)d", "a(c)e"] None: ["a"] Then 'c': 'b': ["b(b)"] 'd': ["ac(d)"] 'e': ["ac(e)"] None: ["a"] Then 'd': 'b': ["b(b)"] 'e': ["ac(e)"] None: ["a", "acd"] Then 'e': 'b': ["b(b)"] None: ["a", "acd", "ace"] And now I just return how many words aren't waiting for anything anymore.