这是一个简单的难题,在生物信息学中有一些应用。这是某位朋友的工作的抽象版本。
考虑一个非常简单的压缩方案,其输出包含两个操作流:
put(a)
:输出字符a
dup()
:复制到目前为止已写入的所有输出为方便起见,请为x
写一个字符put('x')
,为*
写一个dup()
。
例如,"a**b*c"
扩展为"aaaabaaaabc"
。
要压缩给定的字符串s
,请找到这两个操作的最短列表以生成它。
例如"aaaaaaaaaab"
的缩写为a**a*b
。 (a***aab
也可以,但要长一个字符。)
我的问题是:最佳压缩的最佳可实现运行时间是什么? (以及实现该运行时的算法是什么。)
我相信线性运行时是可行的,但是我还没有找到比二次方更好的东西。 (不要太担心使用多余的空间。)
答案 0 :(得分:1)
是的,这种压缩方案可以线性运行。
创建列表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)
中的字符串构建一个suffix array。
然后,为O(n)
中的后缀数组构建一个longest common prefix array。
现在,在后缀数组中找到完整字符串的索引。假设它是i
。现在,从i
迭代到LCP数组的末尾,将每个值替换为到目前为止所看到的最小值。同样,在LCP数组中从i-1
向下迭代到0
,将每个值替换为到目前为止的最小值。
完成此操作后,LCP数组中的每个值将代表带有完整字符串的后缀的最长公共前缀,这是算法所需的。 请注意,这些值是根据排序后缀而不是字符串中后缀的位置进行排序的。不过,使用后缀数组进行映射非常简单。