【发布时间】:2014-08-30 22:20:21
【问题描述】:
通过重复对输入序列应用替换,我将如何合理有效地找到可能的最短输出?我相信(如果我错了,请纠正我)在最坏的情况下这是指数时间,但由于下面的第二个约束,我不确定。天真的方法当然是。
我尝试编写朴素方法(对于所有可能的替换,对于所有有效位置,在该位置应用替换后递归输入的副本。返回所有有效递归和输入中最短的一个,并启用缓存捕获等效替换序列的函数),但它(不可行)很慢,我很确定这是一个算法问题,而不是实现。
有几件事可能会(或可能不会)有所作为:
- 令牌是枚举类型。
- 映射中每个条目的输出长度严格小于条目的输入。
- 我确实不需要完成了哪些替换以及在哪里完成了替换,只需要生成的序列。
因此,作为每个字符都是令牌的示例(为简单起见),如果我将替换映射为 aaba -> a、aaa -> ab 和 aba - > bb,我申请了 minimumString('aaaaa'),我想得到 'a'。
实际的方法签名大致如下:
List<Token> getMinimalAfterReplacements(List<Token> inputList, Map<List<Token>, List<Token>> replacements) {
?
}
有没有比暴力破解更好的方法?如果没有,是否有可以利用的 SAT 库或类似的库?当使用不同的令牌列表但使用相同的替换地图多次调用时,是否可以对地图进行任何预处理以使其更快?
【问题讨论】:
-
我希望您从问题陈述开始。所以你从
aaaaa到a通过a(aaa)a -> a(ab)a = (aaba) -> a,是这样吗? -
第二个约束使它可判定(直观地说,如果某些替换使字符串变长,那么最短字符串的路径可能会通过任意大的字符串;如果没有替换扩展字符串存在有限数量的可能性)。整个事情看起来很像识别上下文相关的语法,它是 PSPACE 完备的,因此即使您相信 P=NP,也不太可能在多项式时间内实现。但是,这只是针对最坏情况的复杂性。您的大多数实际问题可能更简单。另外,启发式方法可以接受吗?
-
@Ben - 正确。我没有把它放在第一位,因为要么我必须在示例中处理 Java 的(荒谬的)冗长,要么不清楚我正在处理一个标记列表而不是字符串。我应该编辑它以将问题陈述放在第一位吗?
-
我可以想象一些低级技巧可以带来一些加速因子,例如 4 或 10。它对你有用吗?目前的时间是什么,需要什么?多任务处理呢?有多少不同的标记,规则如何,输入长度是多少?所有这些信息都可以帮助进行低级优化。
-
@maaartinus 指数增长的诅咒是只有一个非常狭窄的窗口可以帮助这种恒定的因子改进。最迟当添加单个令牌会增加数年的计算时间时,即使是 1000 倍的加速也无济于事。 也许 OP的应用程序都落入那个狭窄的窗口,但必须先检查。
标签: java performance algorithm optimization