gpt4 book ai didi

algorithm - 我怎样才能加快我的 Aho-Corasick 算法?

转载 作者:塔克拉玛干 更新时间:2023-11-03 06:10:12 27 4
gpt4 key购买 nike

我正在尝试解决 HackerRank 上的一个问题; “确定 DNA 健康状况。”在查看了一些讨论后,我决定 Aho-Corasick 算法将是最佳选择。该问题涉及在字符串中搜索具有关联值的各种序列。任务是从给定列表中取出这些序列值对的一部分,并找到与输入字符串关联的值。这意味着要用 100000 个序列值对的列表完成 44850 次。我已经实现了这个算法,虽然它比我第一次尝试快了很多,但它仍然不够快,无法通过这个测试用例。这是我的实现:

构建特里:

def createValueTrie(gs: Array[(String, Int)]): TrieNodeWithVal = {
def recurse(genes: Array[(String, Int)]): Map[Char, TrieNodeWithVal] = {
genes
.groupBy(_._1.head)
.map(x => (x._1, x._2.map(y => (y._1.tail, y._2))))
.map{
case (c, arr: Array[(String, Int)]) => {
val value = arr.filter(_._1.length == 0).foldLeft(0)(_ + _._2)
val filtered = arr.filter(_._1.length > 0)
val recursed = recurse(filtered)
(c, new TrieNodeWithVal(arr.exists(_._1.length == 0), recursed, value))
}
}
}
new TrieNodeWithVal(false, recurse(gs), 0)
}

通过 trie 搜索:

def findValueMatches(trie: TrieNodeWithVal, sequence: String): Iterator[(String, Long)] = {
sequence.scanRight("")(_ + _).dropRight(1).iterator.flatMap(s => {
Iterator.iterate[(Iterator[Char], Option[TrieNodeWithVal])]((s.iterator, Some(trie))) {
case (it: Iterator[Char], Some(node)) => if (it.hasNext) (it, node(it.next())) else (it, None)
case (it: Iterator[Char], None) => (it, None)
}.takeWhile {
case (_, Some(_)) => true
case _ => false
}.map {
case (_, Some(node)) => node
}.zipWithIndex.withFilter {
case (node, _) => node isWord
}.map {
case (node, i) => (s.slice(0, i), node.value)
}
})
}

Trie 节点类:

class TrieNode(isAWord: Boolean, childs: Map[Char, TrieNode]) {
val isWord = isAWord
val children: Map[Char, TrieNode] = childs

def apply(c: Char): Option[TrieNode] = children.get(c)

override def toString(): String = "(" + children.map(x => (if (x._2.isWord) x._1.toUpper else x._1) + ": " + x._2.toString()).mkString(", ") + ")"
}

class TrieNodeWithVal(isAWord: Boolean, childs: Map[Char, TrieNodeWithVal], valu: Long) extends TrieNode(isAWord, childs) {
val value = valu
override val children: Map[Char, TrieNodeWithVal] = childs

override def toString(): String = "(" + children.map(x => (if (x._2.isWord) x._1.toUpper + "[" + x._2.value + "]" else x._1) + ": " + x._2.toString()).mkString(", ") + ")"

override def apply(c: Char): Option[TrieNodeWithVal] = children.get(c)
}

我知道这里可以为失败案例做更多的边缘构建,但讨论中的几个人说它会更慢,因为需要为每个查询重建 trie。对于这样的问题,我应该使用一些更有效的集合吗?如何在保持纯函数式风格的同时加快速度?

最佳答案

有各种变化,有些可能会影响性能,有些只是装饰性的。

recurse 中,您可以组合两个 map 调用并使用 partition 来减少测试数组的次数:

def recurse(genes: Array[(String, Int)]): Map[Char, TrieNodeWithVal] = {
genes
.groupBy(_._1.head)
.map { x =>
val c = x._1
val arr = x._2.map(y => (y._1.tail, y._2))

val (filtered, nonFiltered) = arr.partition(_._1.nonEmpty)
val value = nonFiltered.foldLeft(0)(_ + _._2)
val recursed = recurse(filtered)
(c, new TrieNodeWithVal(nonFiltered.nonEmpty, recursed, value))
}
}

您可以通过在 case 语句上使用条件并组合一些操作来简化 findValueMatches:

def findValueMatches(trie: TrieNodeWithVal, sequence: String): Iterator[(String, Long)] = {
sequence.scanRight("")(_ + _).dropRight(1).iterator.flatMap(s => {
Iterator.iterate[(Iterator[Char], Option[TrieNodeWithVal])]((s.iterator, Some(trie))) {
case (it: Iterator[Char], Some(node)) if it.hasNext => (it, node(it.next()))
case (it: Iterator[Char], _) => (it, None)
}.takeWhile {
_._2.nonEmpty
}.zipWithIndex.collect {
case ((_, Some(node)), i) if node.isWord =>
(s.slice(0, i), node.value)
}
})
}

最后,您可以使用val 参数来简化您的类

class TrieNode(val isWord: Boolean, val children: Map[Char, TrieNode]) {
def apply(c: Char): Option[TrieNode] = children.get(c)

override def toString(): String = "(" + children.map(x => (if (x._2.isWord) x._1.toUpper else x._1) + ": " + x._2.toString()).mkString(", ") + ")"
}

class TrieNodeWithVal(isAWord: Boolean, childs: Map[Char, TrieNodeWithVal], val value: Long) extends TrieNode(isAWord, childs) {
override val children: Map[Char, TrieNodeWithVal] = childs

override def toString(): String = "(" + children.map(x => (if (x._2.isWord) x._1.toUpper + "[" + x._2.value + "]" else x._1) + ": " + x._2.toString()).mkString(", ") + ")"

override def apply(c: Char): Option[TrieNodeWithVal] = children.get(c)
}

这是全部编译但未经测试,如果我无意中更改了算法,我们深表歉意。

关于algorithm - 我怎样才能加快我的 Aho-Corasick 算法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50576168/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com