import java.util.*;
/*
To avoid duplicates with with skips we need to find start nodes that are as close as possible to the root
If it is not possible to find a node for a prefix with a given amount of errors, ONLY then we try to apply skips
*/
class Solution {
static final int ERRORS_ALLOWED = 2;
static class TrieNode {
Map
<Character, TrieNode
> map
= new HashMap
<>(); }
TrieNode root = new TrieNode();
public Solution(List<String> dictionary) {
for (String word
: dictionary
) { TrieNode cur = root;
for (char c : word.toCharArray()) {
if (!cur.map.containsKey(c)) {
TrieNode next = new TrieNode();
cur.map.put(c, next);
}
cur = cur.map.get(c);
}
cur.word = word;
}
}
List
<String
> getWords
(String prefix
) { List<TrieNode> startNodes = getStartNodes(root, prefix, 0, 0);
List<String> words = new ArrayList<>();
for (TrieNode node : startNodes) {
words.addAll(getAllWords(node));
}
return words;
}
private List<String> getAllWords(TrieNode node) {
List<String> words = new ArrayList<>();
if (node.word != null) {
words.add(node.word);
}
for (TrieNode next : node.map.values()) {
words.addAll(getAllWords(next));
}
return words;
}
private List
<TrieNode
> getStartNodes
(TrieNode node,
String prefix,
int ind,
int errors
) { List<TrieNode> res = new ArrayList<>();
if (ind >= prefix.length()) {
}
char charOfPrefix = prefix.charAt(ind);
if (node.map.containsKey(charOfPrefix)) {
res.addAll(getStartNodes(node.map.get(charOfPrefix), prefix, ind + 1, errors));
}
if (errors < ERRORS_ALLOWED) {
for (char c : node.map.keySet()) {
if (node.map.containsKey(charOfPrefix) && c == charOfPrefix) {
continue;
}
List<TrieNode> withPrefixShift = getStartNodes(node.map.get(c), prefix, ind + 1, errors + 1);
res.addAll(withPrefixShift);
if (withPrefixShift.isEmpty()) {
res.addAll(getStartNodes(node.map.get(c), prefix, ind, errors + 1));
}
}
}
return res;
}
public static void main
(String[] args
) { testSkipNotNeeded();
testSkipNeeded();
}
/**
* Removing condition at line 69 leads to duplicate "abzd"
*/
static void testSkipNotNeeded() {
List
<String
> dictionary
= List.
of("abc",
"doecm",
"abzd",
"azfs",
"kzcs"); Solution solution = new Solution(dictionary);
List<String> words = solution.getWords("abc");
}
/**
* Removing lines 69-71 leads to empty result
*/
static void testSkipNeeded() {
List
<String
> dictionary
= List.
of("abzd",
"helloaaa"); Solution solution = new Solution(dictionary);
List<String> words = solution.getWords("heoaa");
}
}
aW1wb3J0IGphdmEudXRpbC4qOwoKLyoKVG8gYXZvaWQgZHVwbGljYXRlcyB3aXRoIHdpdGggc2tpcHMgd2UgbmVlZCB0byBmaW5kIHN0YXJ0IG5vZGVzIHRoYXQgYXJlIGFzIGNsb3NlIGFzIHBvc3NpYmxlIHRvIHRoZSByb290CklmIGl0IGlzIG5vdCBwb3NzaWJsZSB0byBmaW5kIGEgbm9kZSBmb3IgYSBwcmVmaXggd2l0aCBhIGdpdmVuIGFtb3VudCBvZiBlcnJvcnMsIE9OTFkgdGhlbiB3ZSB0cnkgdG8gYXBwbHkgc2tpcHMKICovCgpjbGFzcyBTb2x1dGlvbiB7CgogICAgc3RhdGljIGZpbmFsIGludCBFUlJPUlNfQUxMT1dFRCA9IDI7CgogICAgc3RhdGljIGNsYXNzIFRyaWVOb2RlIHsKICAgICAgICBNYXA8Q2hhcmFjdGVyLCBUcmllTm9kZT4gbWFwID0gbmV3IEhhc2hNYXA8PigpOwogICAgICAgIFN0cmluZyB3b3JkID0gbnVsbDsKICAgIH0KCiAgICBUcmllTm9kZSByb290ID0gbmV3IFRyaWVOb2RlKCk7CgogICAgcHVibGljIFNvbHV0aW9uKExpc3Q8U3RyaW5nPiBkaWN0aW9uYXJ5KSB7CiAgICAgICAgZm9yIChTdHJpbmcgd29yZCA6IGRpY3Rpb25hcnkpIHsKICAgICAgICAgICAgVHJpZU5vZGUgY3VyID0gcm9vdDsKICAgICAgICAgICAgZm9yIChjaGFyIGMgOiB3b3JkLnRvQ2hhckFycmF5KCkpIHsKICAgICAgICAgICAgICAgIGlmICghY3VyLm1hcC5jb250YWluc0tleShjKSkgewogICAgICAgICAgICAgICAgICAgIFRyaWVOb2RlIG5leHQgPSBuZXcgVHJpZU5vZGUoKTsKICAgICAgICAgICAgICAgICAgICBjdXIubWFwLnB1dChjLCBuZXh0KTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGN1ciA9IGN1ci5tYXAuZ2V0KGMpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGN1ci53b3JkID0gd29yZDsKICAgICAgICB9CiAgICB9CgogICAgTGlzdDxTdHJpbmc+IGdldFdvcmRzKFN0cmluZyBwcmVmaXgpIHsKICAgICAgICBMaXN0PFRyaWVOb2RlPiBzdGFydE5vZGVzID0gZ2V0U3RhcnROb2Rlcyhyb290LCBwcmVmaXgsIDAsIDApOwogICAgICAgIExpc3Q8U3RyaW5nPiB3b3JkcyA9IG5ldyBBcnJheUxpc3Q8PigpOwogICAgICAgIGZvciAoVHJpZU5vZGUgbm9kZSA6IHN0YXJ0Tm9kZXMpIHsKICAgICAgICAgICAgd29yZHMuYWRkQWxsKGdldEFsbFdvcmRzKG5vZGUpKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHdvcmRzOwogICAgfQoKICAgIHByaXZhdGUgTGlzdDxTdHJpbmc+IGdldEFsbFdvcmRzKFRyaWVOb2RlIG5vZGUpIHsKICAgICAgICBMaXN0PFN0cmluZz4gd29yZHMgPSBuZXcgQXJyYXlMaXN0PD4oKTsKICAgICAgICBpZiAobm9kZS53b3JkICE9IG51bGwpIHsKICAgICAgICAgICAgd29yZHMuYWRkKG5vZGUud29yZCk7CiAgICAgICAgfQogICAgICAgIGZvciAoVHJpZU5vZGUgbmV4dCA6IG5vZGUubWFwLnZhbHVlcygpKSB7CiAgICAgICAgICAgIHdvcmRzLmFkZEFsbChnZXRBbGxXb3JkcyhuZXh0KSk7CiAgICAgICAgfQogICAgICAgIHJldHVybiB3b3JkczsKICAgIH0KCiAgICBwcml2YXRlIExpc3Q8VHJpZU5vZGU+IGdldFN0YXJ0Tm9kZXMoVHJpZU5vZGUgbm9kZSwgU3RyaW5nIHByZWZpeCwgaW50IGluZCwgaW50IGVycm9ycykgewogICAgICAgIExpc3Q8VHJpZU5vZGU+IHJlcyA9IG5ldyBBcnJheUxpc3Q8PigpOwogICAgICAgIGlmIChpbmQgPj0gcHJlZml4Lmxlbmd0aCgpKSB7CiAgICAgICAgICAgIHJldHVybiBDb2xsZWN0aW9ucy5zaW5nbGV0b25MaXN0KG5vZGUpOwogICAgICAgIH0KICAgICAgICBjaGFyIGNoYXJPZlByZWZpeCA9IHByZWZpeC5jaGFyQXQoaW5kKTsKICAgICAgICBpZiAobm9kZS5tYXAuY29udGFpbnNLZXkoY2hhck9mUHJlZml4KSkgewogICAgICAgICAgICByZXMuYWRkQWxsKGdldFN0YXJ0Tm9kZXMobm9kZS5tYXAuZ2V0KGNoYXJPZlByZWZpeCksIHByZWZpeCwgaW5kICsgMSwgZXJyb3JzKSk7CiAgICAgICAgfQogICAgICAgIGlmIChlcnJvcnMgPCBFUlJPUlNfQUxMT1dFRCkgewogICAgICAgICAgICBmb3IgKGNoYXIgYyA6IG5vZGUubWFwLmtleVNldCgpKSB7CiAgICAgICAgICAgICAgICBpZiAobm9kZS5tYXAuY29udGFpbnNLZXkoY2hhck9mUHJlZml4KSAmJiBjID09IGNoYXJPZlByZWZpeCkgewogICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgTGlzdDxUcmllTm9kZT4gd2l0aFByZWZpeFNoaWZ0ID0gZ2V0U3RhcnROb2Rlcyhub2RlLm1hcC5nZXQoYyksIHByZWZpeCwgaW5kICsgMSwgZXJyb3JzICsgMSk7CiAgICAgICAgICAgICAgICByZXMuYWRkQWxsKHdpdGhQcmVmaXhTaGlmdCk7CiAgICAgICAgICAgICAgICBpZiAod2l0aFByZWZpeFNoaWZ0LmlzRW1wdHkoKSkgewogICAgICAgICAgICAgICAgICAgIHJlcy5hZGRBbGwoZ2V0U3RhcnROb2Rlcyhub2RlLm1hcC5nZXQoYyksIHByZWZpeCwgaW5kLCBlcnJvcnMgKyAxKSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuIHJlczsKICAgIH0KCiAgICBwdWJsaWMgc3RhdGljIHZvaWQgbWFpbihTdHJpbmdbXSBhcmdzKSB7CiAgICAgICAgdGVzdFNraXBOb3ROZWVkZWQoKTsKICAgICAgICB0ZXN0U2tpcE5lZWRlZCgpOwogICAgfQoKICAgIC8qKgogICAgICogUmVtb3ZpbmcgY29uZGl0aW9uIGF0IGxpbmUgNjkgbGVhZHMgdG8gZHVwbGljYXRlICJhYnpkIgogICAgICovCiAgICBzdGF0aWMgdm9pZCB0ZXN0U2tpcE5vdE5lZWRlZCgpIHsKICAgICAgICBMaXN0PFN0cmluZz4gZGljdGlvbmFyeSA9IExpc3Qub2YoImFiYyIsICJkb2VjbSIsICJhYnpkIiwgImF6ZnMiLCAia3pjcyIpOwogICAgICAgIFNvbHV0aW9uIHNvbHV0aW9uID0gbmV3IFNvbHV0aW9uKGRpY3Rpb25hcnkpOwogICAgICAgIExpc3Q8U3RyaW5nPiB3b3JkcyA9IHNvbHV0aW9uLmdldFdvcmRzKCJhYmMiKTsKICAgICAgICBTeXN0ZW0ub3V0LnByaW50bG4od29yZHMpOwogICAgfQoKICAgIC8qKgogICAgICogUmVtb3ZpbmcgbGluZXMgNjktNzEgbGVhZHMgdG8gZW1wdHkgcmVzdWx0CiAgICAgKi8KICAgIHN0YXRpYyB2b2lkIHRlc3RTa2lwTmVlZGVkKCkgewogICAgICAgIExpc3Q8U3RyaW5nPiBkaWN0aW9uYXJ5ID0gTGlzdC5vZigiYWJ6ZCIsICJoZWxsb2FhYSIpOwogICAgICAgIFNvbHV0aW9uIHNvbHV0aW9uID0gbmV3IFNvbHV0aW9uKGRpY3Rpb25hcnkpOwogICAgICAgIExpc3Q8U3RyaW5nPiB3b3JkcyA9IHNvbHV0aW9uLmdldFdvcmRzKCJoZW9hYSIpOwogICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbih3b3Jkcyk7CiAgICB9Cn0K