Algorithm 简单压缩方案的最佳运行时间
这是一个简单的谜题,在生物信息学中有一些应用。这是一个朋友工作中出现的东西的抽象版本 考虑一个非常简单的压缩方案,其输出由两个操作流组成:Algorithm 简单压缩方案的最佳运行时间,algorithm,big-o,lossless-compression,Algorithm,Big O,Lossless Compression,这是一个简单的谜题,在生物信息学中有一些应用。这是一个朋友工作中出现的东西的抽象版本 考虑一个非常简单的压缩方案,其输出由两个操作流组成: put(a):输出字符a dup():复制到目前为止写入的所有输出 为便于注释,请为put('x')编写字符x本身,为dup()编写字符* 例如,“a**b*c”扩展为“aaaaaabc” 要压缩给定字符串s,请找到这两个操作中最短的列表以生成它 例如,对于“aaaaaaaa b”缩短为a**a*b。(a***aab也可以,但长一个字符。) 我的问题是:
:输出字符put(a)
a
:复制到目前为止写入的所有输出dup()
put('x')
编写字符x
本身,为dup()
编写字符*
例如,“a**b*c”
扩展为“aaaaaabc”
要压缩给定字符串s
,请找到这两个操作中最短的列表以生成它
例如,对于“aaaaaaaa b”
缩短为a**a*b
。(a***aab
也可以,但长一个字符。)
我的问题是:实现最佳压缩的最佳运行时是什么?(实现该运行时的算法是什么。)
我相信线性运行时是可能的,但我还没有发现比二次运行时更好的方法。(不要太担心使用额外的空间。)是的,此压缩方案可以使用线性运行时间 创建一个列表
dp
。此列表的第i个元素将是字符串的第一个i
元素的最佳压缩
dp[1] = 1
dp[i] = dp[i-1] + 1
if i is even and first i/2 elements of string are equal to second i/2 elements:
dp[i] = min(dp[i], dp[i/2] + 1)
要检查第一个i/2
元素是否等于第二个i/2
元素,可以在字符串和从索引i/2
开始的后缀之间找到最长的公共前缀。如果此前缀的长度大于或等于i/2
,则第一个i/2
元素实际上等于第二个i/2
元素
使用改进的LCP阵列可以加速此操作
首先,为O(n)
中的字符串构建一个
然后,为O(n)
中的后缀数组构建一个
现在,在后缀数组中找到完整字符串的索引。假设它是i
。现在,从i
迭代到LCP数组的末尾,用迄今为止看到的最小值替换每个值。类似地,在LCP数组中从i-1
向下迭代到0
,用迄今为止看到的最小值替换每个值
完成此操作后,LCP数组中的每个值表示该后缀的最长公共前缀和完整字符串,这是算法所需的。
请注意,这些值是根据已排序的后缀排序的,而不是根据后缀在字符串中的位置排序的。不过,使用后缀数组映射它相当简单。如何?如果您有想法,请添加答案。谢谢。明天我会详细讨论这个问题。根据我的文献研究,我已经期望LCP和后缀数组可能有用。我还为一个简单的算法绘制了一个草图,其中包含两个滚动哈希:基本上,从[0:I]滚动一个,从[I:2*I]滚动另一个。拉宾指纹可能有用。@Matthias是的,指纹识别听起来像是一个简单得多的想法,在实际场景中可能已经足够好了。哦,我认为在实践中,大多数情况下,天真的方法会工作得很快(比最坏情况下的二次行为快得多)。顺便说一句,我认为你可以在你的解决方案中放弃动态规划,使用贪婪,如果你在你的字符串中向后走的话。为了让指纹识别在理论上起作用,我必须很好地处理错误概率。(到目前为止,我只通过指纹识别实现了O(n log n)运行时。)PS请也看看。顺便说一句,开始时的动态编程位是多余的。后面的贪婪很好用。我也发现了一个新的更简单的线性方案。我很快就要发帖了。