Question
有一个长度为 n 的字符串 str,有非常多的关键字 query(长度不超过 10),需要判断每个关键字是否是 str 的子串。
注意:query 是动态的输入进行查询的,预先并不知道所有的 query。
Solution
Best idea of the solution is to use Suffix Tree and similar alternatives.
Solution 1 is an nice idea using HashMap.
我是把所有长度< =10 的子串,哈希一下存放到 10 个哈希表中。
至于哈希函数的选取,随便选一个应该都不会超时。
Solution 2 is using ‘suffix array‘. The most important point of this idea is to only make a substring instance for every 10 characters.
只用=10 的子串。然后二分查找
用=10 的字串排序即可,如包含更短的串会使得预处理变成 O(10nlg(10n))。 查找的复杂度可能没什么变化,使用<=10 会是 O(lg(10n)),而只使用=10 子串初始化的话,因为可能还要进行短 query 跟长子串间的前缀比较,复杂度会是 O(10lgn),稍微有点提高。
Which is to say, using substring length == 10, we comsume less time for pre-processing, and a little more time when querying.
Code
Suffix tree solution from here, note written by me
private List<String> prefixList;
// pre-process the large string
public void initWithString(String str) {
Set<String> strs = new HashSet<String>();
for(int i = 0; i < str.length(); ++i) {
strs.add(str.substring(i, Math.min(str.length(), i + 10)));
}
prefixList = new ArrayList<String>(strs);
Collections.sort(prefixList);
}
// find the query substring
public boolean existSubString(String query) {
int low = 0;
int high = prefixList.size() - 1;
while(low <= high) {
int mid = (low + high) / 2;
int comp = prefixList.get(mid).compareTo(query);
if(comp == 0) {
return true;
}
if(prefixList.get(mid).startsWith(query)) {
return true;
}
if(comp > 0) //mid > query
{
high = mid - 1;
}else{
low = mid + 1;
}
}
return false;
}