假设我有以下字符串:
ABCADCADCADABC
我想通过查找重复的子串来压缩它。 什么算法能提供最佳压缩效果?
在上面的示例中,它应该返回
AB*1 CAD*3 ABC*1
为了进行比较,贪婪算法可能会返回
ABC*1 ADC*2 AD*1 ABC*1
答案 0 :(得分:3)
根据您是喜欢快速,简单还是高压缩比,您可以查看Lempel-Ziv-Welch (LZW)或Lempel-Ziv-Markov chain (LZMA)算法。他们都保留了重复字符串的字典。
答案 1 :(得分:3)
这听起来像是后缀数组/树的作业!
http://en.wikipedia.org/wiki/Suffix_array
您可以使用在字符串上构建的后缀数组来确定重复的模式。例如,我们可以在你的例子中构建一个后缀数组,如下所示(我总是在每个字母之后使用$,你可以对它进行排序,以便$在每个字母之前出现......任何一种方式都可以工作):
ABCADCADCADABC$ ABC$ ADABC$ ADCADABC$ ADCADCADABC$ BCADCADCADABC$ BC$ CADABC$ CADCADABC$ CADCADCADABC$ C$ DABC$ DCADABC$ DCADCADABC$ $
由此,我们可以更容易地看到字符串中的常见模式。使用此后缀数组表示中的信息,我们可以看到CAD在局部区域重复3次,我们可能会使用它作为压缩的选择。 ADC和DCA等不那么吸引人,因为它们压缩的字符串较少。
http://en.wikipedia.org/wiki/Suffix_tree
后缀树是执行相同任务的更有效方法。一旦你围绕如何使用后缀数组做一些事情,那么进入后缀树并不是太过分了。实际上,这用于流行的压缩算法,包括LZW 1和BWT(Bzip)2。
答案 2 :(得分:2)
它可能没有实际意义,但对于您要求的特定问题,有一个动态编程解决方案。如果您已经计算出从第一个字符开始压缩长度为1,2,3 ... n-1的字符串的最佳方法,那么您可以计算从第一个字符开始压缩长度为n的字符串的最佳方法查看每种可能性k的最后k个字符,看看它们是否构成简单字符串的倍数。如果是这样,计算压缩前n个k字符的成本,然后使用字符串的倍数表示最后的k个字符。
所以在你的例子中,你会注意到ABC是自身的倍数,如果你把它表达为ABC * 1,你可以使用你已经为AB CAD *的前11个字符制定的答案3产生AB * 1 CAD * 3 ABC * 1
答案 3 :(得分:1)
更好的是:
ABCAD(6,3)(3,11)
其中(n,d)是匹配的长度和距离。所以(6,3)从三个字节开始复制六个字节。虽然这听起来有点奇怪,但是当它进入三个字节时,它需要的下三个字节已被复制。因此附加CADCAD
。 (3,11)导致ABC
被追加。
这称为LZ77压缩。它是由zip,gzip和zlib使用deflate压缩数据格式实现的。该格式不仅引用了先前的字符串匹配,还对文字(例如ABCAD
)以及长度和距离使用了霍夫曼压缩。