[LeetCode] 792. 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 * 104
1 <= words.length <= 5000
1 <= words[i].length <= 50
s
andwords[i]
consist of only lowercase English letters.
匹配子序列的单词数。
给定字符串 s 和字符串数组 words, 返回 words[i] 中是s的子序列的单词个数 。
字符串的 子序列 是从原始字符串中生成的新字符串,可以从中删去一些字符(可以是none),而不改变其余字符的相对顺序。
例如, “ace” 是 “abcde” 的子序列。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/number-of-matching-subsequences
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路是桶排序。题意不难理解,给了一个字符串 s 和一串单词,请你计算有多少单词属于 s 的子序列。暴力解是把单词一个个拿出来看,用双指针的办法去跟 s 比较,看每个单词到底是不是 s 的子序列。这个做法可行,但是在 s 很长的情况下是会超时的。
一个相对优化的思路是桶排序。这里我们创建一个hashmap<Character, deque<String>>,key是26个字母,value是一个队列,队列里存的是所有首字母为 X 的单词。
首先第一轮初始化遍历 words 数组,把每个单词依据他们首字母的不同,放入 hashmap 的不同 key 下面。接着我们开始遍历字符串 s,每遇到一个字母 X,我们就去 hashmap 中拿出字母 X 背后对应的队列 queue。queue 中的单词都是首字母为 X 的单词。我们遍历这些单词,如果这时我们发现某个单词已经遍历完毕,说明这个单词就是 s 的子序列。对于没有遍历完的单词,去掉他的首字母,把 word.substring(1) 根据他当前新的首字母是什么,再放入hashmap中另外一个key背后的队列继续循环。
举例,比如题目中的第一个例子,我们创建了hashmap之后,开始遍历 s = "abcde"。一开始我们发现是字母 a,符合首字母为 a 的单词有 "a","acd","ace"。其中因为 "a" 已经遍历完毕,所以他就是满足题意的一个子序列。对于 "acd" 和 "ace" ,我们去掉他们的首字母,把 "cd" 和 "ce" 加入 hashmap 中 key 为 "c" 的那个队列继续参与遍历。
此时我们遍历到了字母 b,s = "abcde"。因为 hashmap 中没有首字母是 b 的单词所以直接看下一个字母。此时我们遍历到了字母 c,s = "abcde"。此时 "cd" 和 "ce" 都满足首字母为 "c",我们再把这两个单词分别去掉他们的首字母,再放回 hashmap 中 key 为 "d" 和 "e" 的队列。依据这个思路,最后 "cd" 和 "ce" 也都会被遇到,所以最后答案是有 3 个单词是 s 的子序列。
时间O(n^2) - worst case,所有单词都是 s 的子序列且所有单词都跟 s 一样长
空间O(n) - hashmap
Java实现
1 class Solution { 2 public int numMatchingSubseq(String s, String[] words) { 3 HashMap<Character, Deque<String>> map = new HashMap<>(); 4 for (char c = 'a'; c <= 'z'; c++) { 5 map.put(c, new ArrayDeque<>()); 6 } 7 // 把所有的单词按照首字母不同放入hashmap 8 for (String word : words) { 9 map.get(word.charAt(0)).offer(word); 10 } 11 12 int count = 0; 13 for (char c : s.toCharArray()) { 14 Deque<String> queue = map.get(c); 15 int size = queue.size(); 16 for (int i = 0; i < size; i++) { 17 String word = queue.poll(); 18 if (word.length() == 1) { 19 count++; 20 } else { 21 map.get(word.charAt(1)).offer(word.substring(1)); 22 } 23 } 24 } 25 return count; 26 } 27 }