Hard
Given an array of strings words
(without duplicates), return all the concatenated words in the given list of words
.
A concatenated word is defined as a string that is comprised entirely of at least two shorter words in the given array.
Example 1:
Input: words = [“cat”,”cats”,”catsdogcats”,”dog”,”dogcatsdog”,”hippopotamuses”,”rat”,”ratcatdogcat”]
Output: [“catsdogcats”,”dogcatsdog”,”ratcatdogcat”]
Explanation: “catsdogcats” can be concatenated by “cats”, “dog” and “cats”; “dogcatsdog” can be concatenated by “dog”, “cats” and “dog”; “ratcatdogcat” can be concatenated by “rat”, “cat”, “dog” and “cat”.
Example 2:
Input: words = [“cat”,”dog”,”catdog”]
Output: [“catdog”]
Constraints:
1 <= words.length <= 104
1 <= words[i].length <= 30
words[i]
consists of only lowercase English letters.words
are unique.1 <= sum(words[i].length) <= 105
class Solution {
private val ans: MutableList<String> = ArrayList()
private var root: Trie? = null
fun findAllConcatenatedWordsInADict(words: Array<String>): List<String> {
root = Trie()
words.sortWith { a: String, b: String ->
a.length.compareTo(b.length)
}
for (word in words) {
var ptr = root
if (search(word, 0, 0)) {
ans.add(word)
} else {
for (j in 0 until word.length) {
if (ptr!!.nxt[word[j].code - 'a'.code] == null) {
ptr.nxt[word[j].code - 'a'.code] = Trie()
}
ptr = ptr.nxt[word[j].code - 'a'.code]
}
ptr!!.endHere = true
}
}
return ans
}
private fun search(cur: String, idx: Int, wordCnt: Int): Boolean {
if (idx == cur.length) {
return wordCnt >= 2
}
var ptr = root
for (i in idx until cur.length) {
if (ptr!!.nxt[cur[i].code - 'a'.code] == null) {
return false
}
if (ptr.nxt[cur[i].code - 'a'.code]!!.endHere) {
val ret = search(cur, i + 1, wordCnt + 1)
if (ret) {
return true
}
}
ptr = ptr.nxt[cur[i].code - 'a'.code]
}
return ptr!!.endHere && wordCnt >= 2
}
private class Trie internal constructor() {
var nxt: Array<Trie?>
var endHere: Boolean
init {
nxt = arrayOfNulls(26)
endHere = false
}
}
}