Given a string s and an array of strings words, return the number ofwords[i]that is a subsequence ofs.
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 each word, we want to check if it is a subsequence of s. Instead of scanning s for each word, we preprocess s: for each character, store all its indices. For each word, for each character, use binary search to find the next occurrence after the previous character’s index.
#include<vector>#include<string>#include<unordered_map>#include<algorithm>usingnamespace std;
classSolution {
public:int numMatchingSubseq(string s, vector<string>& words) {
unordered_map<char, vector<int>> idx;
for (int i =0; i < s.size(); ++i) idx[s[i]].push_back(i);
int ans =0;
for (auto& w : words) {
int prev =-1, ok =1;
for (char c : w) {
auto& v = idx[c];
auto it = upper_bound(v.begin(), v.end(), prev);
if (it == v.end()) { ok =0; break; }
prev =*it;
}
ans += ok;
}
return ans;
}
};
import java.util.*;
classSolution {
publicintnumMatchingSubseq(String s, String[] words) {
Map<Character, List<Integer>> idx =new HashMap<>();
for (int i = 0; i < s.length(); ++i) {
idx.computeIfAbsent(s.charAt(i), k ->new ArrayList<>()).add(i);
}
int ans = 0;
for (String w : words) {
int prev =-1;
boolean ok =true;
for (char c : w.toCharArray()) {
List<Integer> v = idx.getOrDefault(c, new ArrayList<>());
int j = Collections.binarySearch(v, prev+1);
if (j < 0) j =~j;
if (j == v.size()) { ok =false; break; }
prev = v.get(j);
}
if (ok) ans++;
}
return ans;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
classSolution {
funnumMatchingSubseq(s: String, words: Array<String>): Int {
val idx = mutableMapOf<Char, MutableList<Int>>()
for (i in s.indices) idx.getOrPut(s[i]) { mutableListOf() }.add(i)
var ans = 0for (w in words) {
var prev = -1; var ok = truefor (c in w) {
val v = idx[c] ?: mutableListOf()
val j = v.binarySearch(prev+1)
val jj = if (j < 0) -j-1else j
if (jj == v.size) { ok = false; break }
prev = v[jj]
}
if (ok) ans++ }
return ans
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import bisect
classSolution:
defnumMatchingSubseq(self, s: str, words: list[str]) -> int:
idx = {}
for i, c in enumerate(s):
idx.setdefault(c, []).append(i)
ans =0for w in words:
prev, ok =-1, Truefor c in w:
v = idx.get(c, [])
j = bisect.bisect_right(v, prev)
if j == len(v): ok =False; break prev = v[j]
if ok: ans +=1return ans
use std::collections::HashMap;
impl Solution {
pubfnnum_matching_subseq(s: String, words: Vec<String>) -> i32 {
letmut idx: HashMap<char, Vec<usize>>= HashMap::new();
for (i, c) in s.chars().enumerate() {
idx.entry(c).or_default().push(i);
}
letmut ans =0;
for w in words {
letmut prev = None;
letmut ok =true;
for c in w.chars() {
let v = idx.get(&c).unwrap_or(&vec![]);
let j =match prev {
None => v.first().cloned(),
Some(p) => v.iter().find(|&&x| x > p).cloned(),
};
iflet Some(jj) = j { prev = Some(jj); } else { ok =false; break; }
}
if ok { ans +=1; }
}
ans
}
}