我正在考虑改进前缀树。它允许我搜索包含输入字符串的指定数量的单词。
任务:我们需要一个通过子字符串实现公司名称列表的类——从所有可用名称的列表中,输出以输入行开头的一定数量的公司。假设在具有高 RPS(每秒请求数)的网站/移动应用程序上填写表单时将调用该类。
我的解决方案:
class SuggestService(companyNames : Seq[String]) {
val arrayCompany = companyNames.toArray
val tree = getTree(Ternary.apply, 0)
def getTree(tree: Ternary, index: Int): Ternary = {
if(index == arrayCompany.length-1)
return tree.insert(arrayCompany(index))
getTree(tree.insert(arrayCompany(index)), index+1)
}
def suggest(input: String, numberOfSuggest : Int) : Seq[String] = {
val result = tree.keysWithPrefix(input)
result.take(numberOfSuggest)
}
}
树类:
sealed trait Ternary {
def insert(key: String): Ternary = Ternary.insert(this, key, 0)
def keysWithPrefix(prefix: String): List[String] = Ternary.keys(this, prefix)
}
case class Node(value: Option[Int], char: Char, left: Ternary, mid: Ternary, right: Ternary) extends Ternary
case object Leaf extends Ternary
object Ternary {
def apply: Ternary = Leaf
private def keys(root: Ternary, prefix: String): List[String] =
get(root, prefix, 0) match {
case None => Nil
case Some(node) =>
collect(node, prefix.dropRight(1))
}
private def collect(node: Ternary, prefix: String): List[String] =
node match {
case Leaf => Nil
case node: Node if node.value.isDefined =>
(prefix + node.char) +: (collect(node.left, prefix) ++ collect(node.mid, prefix + node.char) ++ collect(node.right, prefix))
case node: Node =>
collect(node.left, prefix) ++ collect(node.mid, prefix + node.char) ++ collect(node.right, prefix)
}
private def get(root: Ternary, prefix: String, step: Int): Option[Ternary] = root match {
case Leaf => None
case node: Node if node.char > prefix.charAt(step) => get(node.left, prefix, step)
case node: Node if node.char < prefix.charAt(step) => get(node.right, prefix, step)
case node: Node if step < prefix.length - 1 => get(node.mid, prefix, step + 1)
case node: Node => Some(node)
}
private def insert(root: Ternary, key: String, step: Int): Ternary = root match {
case Leaf =>
val node = Node(None, key.charAt(step), Leaf, Leaf, Leaf)
insert(node, key, step)
case node: Node if node.char > key.charAt(step) =>
val left = insert(node.left, key, step)
node.copy(left = left)
case node: Node if node.char < key.charAt(step) =>
val right = insert(node.right, key, step)
node.copy(right = right)
case node: Node if step < key.length - 1 =>
val mid = insert(node.mid, key, step + 1)
node.copy(mid = mid)
case node: Node =>
node.copy(value = Some(0))
}
}
该解决方案运行良好,并且似乎可以非常有效地工作,但我对它的不满程度已经足够了。根据条件,我们必须返回数量等于 numberOfSuggest 数量的单词列表。
我强制树返回所有包含输入的单词。然后我才从结果列表中获取所需数量的单词:
def suggest(input: String, numberOfSuggest : Int) : Seq[String] = {
val result = tree.keysWithPrefix(input)
result.take(numberOfSuggest)
}
我想尽量节省时间,并教树返回一个现成的受 numberOfSuggest 数量限制的单词列表。