Java 迭代字符串替换后的最短可能结果长度

Java 迭代字符串替换后的最短可能结果长度,java,performance,algorithm,optimization,Java,Performance,Algorithm,Optimization,我如何通过对输入序列重复应用替换来合理有效地找到尽可能最短的输出?我相信(如果我错了,请纠正我),在最坏的情况下,这是指数时间,但由于下面的第二个限制,我不确定。天真的方法当然是 我尝试编写Naiver方法(对于所有可能的替换,对于所有有效位置,在该位置应用替换后,在输入副本上递归。返回所有有效递归和输入中最短的一个,并在函数上缓存以捕获等效的替换序列),但它(不可行)很慢,我很确定这是一个算法问题,而不是实现问题 有两件事可能会(也可能不会)产生影响: 令牌是枚举类型 映射中每个条目的输出长

我如何通过对输入序列重复应用替换来合理有效地找到尽可能最短的输出?我相信(如果我错了,请纠正我),在最坏的情况下,这是指数时间,但由于下面的第二个限制,我不确定。天真的方法当然是

我尝试编写Naiver方法(对于所有可能的替换,对于所有有效位置,在该位置应用替换后,在输入副本上递归。返回所有有效递归和输入中最短的一个,并在函数上缓存以捕获等效的替换序列),但它(不可行)很慢,我很确定这是一个算法问题,而不是实现问题

有两件事可能会(也可能不会)产生影响:

  • 令牌是枚举类型
  • 映射中每个条目的输出长度严格小于条目的输入长度
  • 我不需要做什么替换和在哪里,只需要结果序列
因此,作为一个示例,其中每个字符都是一个标记(为了简单起见),如果我将替换映射设置为
aaba
->
a
aaa
->
ab
,以及
aba
->
bb
,并应用最小字符串('aaaaaaa'),我希望得到'a'

实际的方法签名大致如下:

List<Token> getMinimalAfterReplacements(List<Token> inputList, Map<List<Token>, List<Token>> replacements) {
    ?
}
List-getMinimalAfterReplacements(列表输入列表,映射替换){
?
}

有比暴力更好的方法吗?如果没有,是否有可以利用的SAT库或类似库?当使用不同的令牌列表但使用相同的替换映射多次调用时,是否可以对映射进行任何预处理以使其更快?

这只是一个可能减少分支的简单想法:使用如下规则

ba -> c
ca -> b
还有一条像

aaabaacaa
   ^  ^
你可以做两次替换,它们的顺序无关紧要。这在某种程度上已经被memonization覆盖了,但是,生成无用字符串仍然有相当大的开销。因此,我建议遵循以下规则:

在位置<代码> P<代码>之后,只考虑位置“代码> q>代码>的替换,使

q + length(lhs_of_the_rule) > p
i、 例如,这样就不会从先前替换的左侧开始,或者它们重叠



作为一个简单的低级优化,我建议将
列表
替换为
字符串
或(或封装的
字节[]
短[]
或其他内容)。较低的内存占用应该有助于缓存,您可以通过一个(或两个)字符串元素对数组进行索引,以找出适用于该数组的规则。

下面的代码是一个Python版本,用于找到尽可能短的缩减。它是非递归的,但与朴素的算法相差不远。在每一步中,它都会尝试所有可能的单个缩减,从而获得一组字符串,以便在下一步中进行缩减

在存在“aa”->“a”等“符号吃”规则的情况下,有一种优化方法可以帮助检查下一组字符串是否存在重复项

另一个优化(下面的代码中没有实现)是将替换规则处理成一个有限自动机,该自动机通过一次输入字符串查找所有可能的单个缩减的位置。不过,这无助于主树搜索算法的指数性质

类替换程序:
def u u初始(自我,替换):
self.replacements=[[tuple(key),tuple(value)]表示key,replacements.items()中的value]
def获取可能的替换(自身、输入):
“返回对输入进行了单个替换的所有可能变化”
结果=[]
对于替换内容,请在self.replacements中将替换为:
#打印替换什么,替换为
对于范围内的p(1+len(输入)-len(替换_what)):
如果输入[p:p+len(替换内容)]==替换内容:
输入\复制=列表(输入[:])
输入副本[p:p+len(替换内容)]=替换为
结果.追加(元组(输入\复制))
返回结果
def get_最小顺序_列表(自身,输入):
“返回可从给定输入获得的最短不可约序列”
不可约=[]
to_reduce=[元组(输入)]
减少新的数量=[]
步骤=1
而要减少:
打印“缩减步骤”,步骤“”,要缩减的候选数量:,len(要缩减)
步骤+=1
对于要减少的当前\u输入:
减少=自身。获取可能的替换(当前输入)
如果没有减少:
不可约.append(当前_输入)
其他:
减少新的+=减少
to_reduce=set(to_reduce_new[:])#这通过删除重复项显著减少了树的宽度
减少新的数量=[]
不可约_排序=已排序(集合(不可约),键=λx:len(x))
#打印“.join(input)”,可以减少为“,[”.在不可约_排序中为x加入(x)]
返回不可约_排序[0]
def get_最小顺序(自身,输入):
返回“.join(self.get\u minimum\u sequence\u list(list(input)))
输入=“aaaaa”
替换={
“aaba”:“a”,
“aaa”:“ab”,
“aba”:“bb”,
}
替换件=替换件(替换件)
替换=替换。获取最小顺序(输入)
打印“最短字符串”,输入“可缩减为is”,替换

我希望您从问题陈述开始。所以你从
aaaaa
a
是通过
a(aaa)a->a(ab)a=(aaba)->a
得到的,是吗?第二个约束是什么使它可以判定(直观地说,如果某些替换使字符串变长,则最短字符串的路径可能会通过任意大的字符串;如果没有替换,则扩展字符串的可能性是有限的)。整个过程看起来非常类似于识别上下文敏感文法,它是PSPACE完成的,因此