将项目列表分解为可用于表示它的最少组数的算法

问题描述

我很抱歉问了这么宽泛的问题,但我正在为如何开始这个问题而苦苦挣扎。我有一个模糊的想法,我实际上试图做的是压缩算法所做的事情,但实际上我正在寻找某人为我指出我可以用来以此为基础的文章的方向。

基本上我有文件。该文件由多行组成。每行是一个逗号分隔的项目列表。我想生成一个新列表,其中包含这些列表中可用于构建原始文件的最少子集数。

一个例子可能会更好地说明这一点,如果我有一个输入文件

A,B,C,D
E,D
F,D
G,H
A,I,J,D
1,2,3,4,5,6,7,8
9,1

我的输出应该是这样的

A
B,C
D
E
F
G
I,J
1
2,4
5,7
8
9

因为这是我需要建立原始列表的最小唯一组数。

我很确定我在描述压缩算法的工作(尽管我这样做不是为了压缩)但是我找不到任何文档来在字符串数组上实现这样的东西在 C# 中,正如我所尝试的那样-我能找到的最好的方法是用于压缩/解压缩我不想要的字节数组的预构建库。我觉得我最接近的是谷歌搜索“霍夫曼编码”,这似乎符合我正在尝试做的事情,但说实话,我正在努力理解如何根据我正在阅读的内容来实现任何东西。

解决方法

所以你重新发明了Lempel-Zip

这个想法是通过制作从当前位置向后的距离列表和要复制到输出流的长度来制作字典(就像您已经以某种方式制作的一样)。

来自维基百科的 LZ77 伪代码。

while input is not empty do
    prefix := longest prefix of input that begins in window
    
    if prefix exists then
        d := distance to start of prefix
        l := length of prefix
        c := char following prefix in input
    else
        d := 0
        l := 0
        c := first char of input
    end if
    
    output (d,l,c)
    
    discard l + 1 chars from front of window
    s := pop l + 1 chars from front of input
    append s to back of window
repeat

根据您的输入,我们注意到 'A' 是第一个字符并且没​​有前缀,所以 (0,'A') 被写入并且'A'被添加到前缀中。

下一个 'B' 不在前缀中,因此将其添加,(0,'B') 和 'B' 被添加到前缀中,依此类推,直到包含 'E'。

接下来是'B',它已经存在,前缀中的'B'位置是-4,后面的'C'和'D'也在输入中所以长度是3,(-4,3,'F'),'F' 是输入中的下一个。这意味着有时流中的字符会重复,如果您不需要将 \0 表示为字符并将其用作前缀中的无,则可以避免这种情况。

,

看起来很简单:

先试A,看到的第一个字符。 看看它是否总是跟随着同一个字符。回答 AB 和 AI,所以只是 [A]。 将 [A] 添加到列表中。从输入中删除所有 [A]。

尝试 B(找到下一个字符)。看看它是否总是跟随着同一个字符。总是回答 BC,所以是的,现在还要看看 C 是否出现在它前面没有 B 的地方,它没有,所以将 [BC] 添加到列表中。从输入中删除所有 [BC]。

等等。