给定一个较长字符串big和一个包含较短字符串的数组smalls,设计一个方法,根据smalls中的每一个较短字符串,对big进行搜索。输出smalls中的字符串在big里出现的所有位置positions,其中positions[i]为smalls[i]出现的所有位置。
示例:
输入:
big = "mississippi"
smalls = ["is","ppi","hi","sis","i","ssippi"]
输出: [[1,4],[8],[],[3],[1,4,7,10],[5]]
提示:
0 <= len(big) <= 1000
0 <= len(smalls[i]) <= 1000
smalls的总字符数不会超过 100000。
你可以认为smalls中没有重复字符串。
所有出现的字符均为英文小写字母。
思路:big长度只有1000,然而smalls总字符数却有100000这么大,因此普通的暴力做法必然无法通过该题,我们需要找到更优的字符串匹配做法,想想我们有哪些方法可以选择?字典树?kmp?还是AC自动机?其实都ok的,为了简单并容易理解,这里我采用字典树解决该题。
具体思路为:将smalls字符串数组插入字典树中,然后枚举big的每一个后缀(想想为什么只枚举后缀即可),判断字典树中是否存在已有单词,并能同时找到那些字符串是存在的。
class Solution {
class TreeNode {
int flag;
TreeNode[] child;
public TreeNode() {
flag = -1;
child = new TreeNode[26];
}
}
TreeNode root;
List<List<Integer>> list;
public int[][] multiSearch(String big, String[] smalls) {
int m = big.length();
int n = smalls.length;
list = new ArrayList<>();
for (int i = 0; i < n; i++)
list.add(new ArrayList<>());
root = new TreeNode();
for (int i = 0; i < n; i++)
insert(smalls[i], i);
for (int i = 0; i < m; i++)
query(big.substring(i), i);
int[][] ans = new int[n][];
for (int i = 0; i < n; i++) {
int size = list.get(i).size();
ans[i] = new int[size];
for (int j = 0; j < size; j++)
ans[i][j] = list.get(i).get(j);
}
return ans;
}
private void query(String word, int index) {
TreeNode now = root;
int len = word.length();
for (int i = 0; i < len; i++) {
int c = word.charAt(i) - 'a';
if (now.child[c] == null)
return;
now = now.child[c];
if (now.flag != -1)
list.get(now.flag).add(index);
}
}
private void insert(String word, int index) {
TreeNode now = root;
int len = word.length();
for (int i = 0; i < len; i++) {
int c = word.charAt(i) - 'a';
if (now.child[c] == null)
now.child[c] = new TreeNode();
now = now.child[c];
}
now.flag = index;
}
}