Description
Given many words, words[i] has weight i.
Design a class WordFilter that supports one function, WordFilter.f(String prefix, String suffix). It will return the word with given prefix and suffix with maximum weight. If no word exists, return -1.
Examples:
Input:
WordFilter(["apple"])
WordFilter.f("a", "e") // returns 0
WordFilter.f("b", "") // returns -1
Note:
- words has length in range [1, 15000].
- For each test case, up to words.length queries WordFilter.f may be made.
- words[i] has length in range [1, 10].
- prefix, suffix have lengths in range [0, 10].
- words[i] and prefix, suffix queries consist of lowercase letters only.
问题描述
给定字符串数组words,words[i]的权重为i。
设计WordsFilter类,支持WordFilter.f(String prefix, String suffix)。
这个函数返回以prefix为前缀,以suffix为后缀的有着最大权重的字符串。
如果没有这样的字符串,那么返回-1。
问题分析
我的做法是通过前缀字典树和后缀字典树找出满足的字符串集合,然后逆序遍历words,判断words[i]是否在字符串集合中(复杂且效率不高)
这个链接记录了另外三种简单的解法,感兴趣的话可以去看看
https://leetcode.com/problems/prefix-and-suffix-search/discuss/110044/Three-ways-to-solve-this-problem-in-Java
解法1(字典树)
class WordFilter {
//前缀字典树节点
private class ptNode{
//拥有该路径为前缀的字符串
boolean[] prefix;
ptNode[] children;
public ptNode(int n){
prefix = new boolean[n];
children = new ptNode[26];
}
}
//后缀字典树节点
private class stNode{
//拥有该路径为后缀的字符串
boolean[] suffix;
stNode[] children;
public stNode(int n){
suffix = new boolean[n];
children = new stNode[26];
}
}
private ptNode proot;
private stNode sroot;
private String[] words;
private int n;
public WordFilter(String[] words) {
n = words.length;
proot = new ptNode(n);
sroot = new stNode(n);
this.words = words;
//遍历words,构造前缀字典树和后缀字典树
for(int i = 0;i < n;i++){
addp(proot, words[i], i);
adds(sroot, words[i], i);
}
}
public int f(String prefix, String suffix) {
ptNode workNode1 = proot;
stNode workNode2 = sroot;
//通过两个循环找出满足指定前缀和后缀的字符串集合
for(char c : prefix.toCharArray()){
workNode1 = workNode1.children[c - 'a'];
if(workNode1 == null) return -1;
}
int i = suffix.length() - 1;
while(i >= 0){
workNode2 = workNode2.children[suffix.charAt(i) - 'a'];
if(workNode2 == null) return -1;
i--;
}
//逆序遍历words,返回满足条件的字符串
for(i = n - 1;i >= 0;i--){
if(workNode1.prefix[i] && workNode2.suffix[i]) return i;
}
return -1;
}
//构造前缀字典树
public void addp(ptNode root, String str, int index){
for(char c : str.toCharArray()){
//在这里维护满足前缀的字符串数组
root.prefix[index] = true;
if(root.children[c - 'a'] == null) root.children[c - 'a'] = new ptNode(n);
root = root.children[c - 'a'];
}
//还有这里
root.prefix[index] = true;
}
//构造后缀字典树
public void adds(stNode root, String str, int index){
int i = str.length() - 1;
char[] cArr = str.toCharArray();
while(i >= 0){
//在这里维护满足后缀的字符串数组
root.suffix[index] = true;
if(root.children[cArr[i] - 'a'] == null) root.children[cArr[i] - 'a'] = new stNode(n);
root = root.children[cArr[i] - 'a'];
i--;
}
//还有这里
root.suffix[index] = true;
}
}
另外两种简单的做法
解法2
class WordFilter {
//存储满足前缀的权重列表
HashMap<String, List<Integer>> mapPrefix = new HashMap<>();
//存储满足后缀的权重列表
HashMap<String, List<Integer>> mapSuffix = new HashMap<>();
public WordFilter(String[] words) {
//循环构建mapPrefix和mapSuffix
for(int w = 0; w < words.length; w++){
for(int i = 0; i <= words[w].length(); i++){
String s = words[w].substring(0, i);
if(!mapPrefix.containsKey(s)) mapPrefix.put(s, new ArrayList<>());
mapPrefix.get(s).add(w);
}
for(int i = 0; i <= words[w].length(); i++){
String s = words[w].substring(words[w].length() - i);
if(!mapSuffix.containsKey(s)) mapSuffix.put(s, new ArrayList<>());
mapSuffix.get(s).add(w);
}
}
}
public int f(String prefix, String suffix) {
if(!mapPrefix.containsKey(prefix) || !mapSuffix.containsKey(suffix)) return -1;
//得出prefix的权重列表
List<Integer> p = mapPrefix.get(prefix);
//得出suffix的权重列表
List<Integer> s = mapSuffix.get(suffix);
int i = p.size()-1, j = s.size()-1;
while(i >= 0 && j >= 0){
if(p.get(i) < s.get(j)) j--;
else if(p.get(i) > s.get(j)) i--;
//若相等,说明找到,直接返回
else return p.get(i);
}
return -1;
}
}
解法3
class WordFilter {
HashMap<String, Integer> map = new HashMap<>();
public WordFilter(String[] words) {
for(int w = 0; w < words.length; w++){
for(int i = 0; i <= words[w].length(); i++){
for(int j = 0; j <= words[w].length(); j++){
map.put(words[w].substring(0, i) + "#" + words[w].substring(words[w].length() - j), w);
}
}
}
}
public int f(String prefix, String suffix) {
return (map.containsKey(prefix + "#" + suffix)) ? map.get(prefix + "#" + suffix) : -1;
}
}