0792. Number of Matching Subsequences - kumaeki/LeetCode GitHub Wiki
0792. Number of Matching Subsequences
Given a string s and an array of strings words, return the number of words[i] that is a subsequence of s.
A subsequence of a string is a new string generated from the original string with some characters (can be none) deleted without changing the relative order of the remaining characters.
For example, "ace" is a subsequence of "abcde".
Example 1:
Input: s = "abcde", words = ["a","bb","acd","ace"]
Output: 3
Explanation: There are three strings in words that are a subsequence of s: "a", "acd", "ace".
Example 2:
Input: s = "dsahjpjauf", words = ["ahjpjau","ja","ahbwzgqnuk","tnmlanowax"]
Output: 2
Constraints:
- 1 <= s.length <= 5 * 10^4
- 1 <= words.length <= 5000
- 1 <= words[i].length <= 50
- s and words[i] consist of only lowercase English letters.
首先想到的是把所有的words放进字典里, 然后用 s 遍历字典, 找到所有匹配的字符并计数. 但是超时了.
class Solution {
public int numMatchingSubseq(String s, String[] words) {
Node root = prepareNode(words);
return getCount(root, s, 0);
}
private Node prepareNode(String[] words){
Node root = new Node('#');
for(String w : words){
Node node = root;
for(char c : w.toCharArray()){
if(node.next[c - 'a'] == null)
node.next[c - 'a'] = new Node(c);
node = node.next[c - 'a'];
}
node.isEnd++;
}
return root;
}
private int getCount(Node node, String s, int index){
if(index == s.length())
return 0;
int res = 0;
Node next = node.next[s.charAt(index) - 'a'];
if(next != null){
if(next.isEnd > 0){
res += next.isEnd;
next.isEnd = 0;
}
res += getCount(next, s, index + 1);
}
return res + getCount(node, s, index + 1);
}
private class Node{
Node[] next;
int isEnd;
public Node(char v){
next = new Node[26];
isEnd = 0;
}
}
}
#解法2
class Solution {
public int numMatchingSubseq(String S, String[] words) {
// 用map来存储以a到z为首字符的字符串的列表
Map<Character, LinkedList<String>> map = new HashMap<Character, LinkedList<String>>();
for (char c = 'a'; c <= 'z'; c++)
map.putIfAbsent(c, new LinkedList<String>());
// 将所有的words放入map
for (String w : words)
map.get(w.charAt(0)).addLast(w);
int res = 0;
// 对于s中的每一个字符
for (char c : S.toCharArray()) {
// 找到所有以当前字符c开头的字符串
LinkedList<String> list = map.get(c);
for (int i = 0, len = list.size(); i < len; i++) {
String str = list.removeFirst();
// 如果字符串长度为1, 那么肯定是符合条件的, 结果数 + 1
if (str.length() == 1)
res++;
// 如果不为1, 那么去掉头字符, 将剩下的字符串存入map中
// 这个步骤每次都会将符合条件的字符长度减1, 直到将长度减少为1
else
map.get(str.charAt(1)).addLast(str.substring(1));
}
}
return res;
}
}
#解法3 解法2中对每个word反复取子字符串其实也很花费时间.
class Solution {
public int numMatchingSubseq(String S, String[] words) {
Map<Character, LinkedList<Item>> map = new HashMap<Character, LinkedList<Item>>(30);
for (char c = 'a'; c <= 'z'; c++)
map.putIfAbsent(c, new LinkedList<Item>());
for (String w : words)
map.get(w.charAt(0)).addLast(new Item(w, 0));
int res = 0;
for (char c : S.toCharArray()) {
LinkedList<Item> list = map.get(c);
for (int i = 0, len = list.size(); i < len; i++) {
Item item = list.removeFirst();
if (item.index == item.word.length() - 1)
res++;
else{
item.index++;
map.get(item.word.charAt(item.index)).addLast(item);
}
}
}
return res;
}
// 用Item来保存原始字符和计算下标, 避免频繁的substring
class Item{
String word;
int index;
public Item(String word, int index){
this.word = word;
this.index = index;
}
}
}