同义词查找器算法

| 我认为示例将比loooong描述好得多:) 假设我们有一个数组数组:
(\"Server1\", \"Server_1\", \"Main Server\", \"192.168.0.3\")
(\"Server_1\", \"VIP Server\", \"Main Server\")
(\"Server_2\", \"192.168.0.4\")
(\"192.168.0.3\", \"192.168.0.5\")
(\"Server_2\", \"Backup\")
每行包含作为同义词的字符串。作为处理此数组的结果,我想得到这个:
(\"Server1\", \"Server_1\", \"Main Server\", \"192.168.0.3\", \"VIP Server\", \"192.168.0.5\")
(\"Server_2\", \"192.168.0.4\", \"Backup\")
所以我认为我需要一种递归算法。编程语言实际上并不重要-一般而言,我只需要一点帮助。我将使用php或python。 谢谢!     
已邀请:
这个问题可以简化为图论中的问题,您可以在图中找到所有连接节点组。 解决此问题的有效方法是执行“洪水填充”算法,该算法本质上是递归呼吸优先搜索。 Wikipedia条目描述了洪水填充算法及其如何解决发现图形的连通区域的问题。 要查看如何将原始问题变成图表上的问题,请执行以下操作:使每个条目(例如\“ Server1 \”,\“ Server_1 \”等)成为图表上的节点。当且仅当它们是同义词时,才用边连接节点。如果您有足够的内存,矩阵数据结构特别适合跟踪边缘。否则,像地图这样的稀疏数据结构将起作用,尤其是由于同义词的数量可能会受到限制。 Server1是节点#0 Server_1是节点#1 Server_2是节点#2 然后edge [0] [1] = edge [1] [0] = 1表示节点#0和#1之间存在一条边(这意味着它们是同义词)。而edge [0] [2] = edge [2] [0] = 0表示Server1和Server_2不是同义词。 复杂度分析 创建此数据结构非常有效,因为只需进行一次线性遍历,即可查找字符串到节点号的映射关系。如果将字符串到节点号的映射关系存储在字典中,则这将是O(n log n)步骤。 进行洪水填充为O(n),您只需访问图形中的每个节点一次。因此,该算法总计为O(n log n)。     
引入整数标记,该标记指示同义词组。在开始时,用words2ѭ到
N
标记所有带有不同标记的单词。 然后搜索集合中的所有单词,如果发现索引为
i
j
的两个词是同义词,则用标记
i
j
的所有词标记较少的两个词。在
N
迭代之后,您将获得所有同义词组。 这是一种肮脏且并非完全有效的解决方案,我相信人们可以通过联合发现的结构获得更高的性能。     
编辑:这可能不是解决问题的最有效方法。如果您对最高性能感兴趣(例如,如果您拥有数百万个值),则可能对编写更复杂的算法感兴趣。 PHP,似乎可以正常工作(至少使用给定示例中的数据):
$data = array(
    array(\"Server1\", \"Server_1\", \"Main Server\", \"192.168.0.3\"),
    array(\"Server_1\", \"VIP Server\", \"Main Server\"),
    array(\"Server_2\", \"192.168.0.4\"),
    array(\"192.168.0.3\", \"192.168.0.5\"),
    array(\"Server_2\", \"Backup\"),
);

do {
    $foundSynonyms = false;
    foreach ( $data as $firstKey => $firstValue ) {
        foreach ( $data as $secondKey => $secondValue ) {
            if ( $firstKey === $secondKey ) {
                continue;
            }
            if ( array_intersect($firstValue, $secondValue) ) {
                $data[$firstKey] = array_unique(array_merge($firstValue, $secondValue));
                unset($data[$secondKey]);
                $foundSynonyms = true;
                break 2; // outer foreach
            }
        }
    }
} while ( $foundSynonyms );

print_r($data);
输出:
Array
(
    [0] => Array
        (
            [0] => Server1
            [1] => Server_1
            [2] => Main Server
            [3] => 192.168.0.3
            [4] => VIP Server
            [6] => 192.168.0.5
        )

    [2] => Array
        (
            [0] => Server_2
            [1] => 192.168.0.4
            [3] => Backup
        )

)
    
与PHP示例(Python 3)相比,这将降低复杂度:
a = [set((\"Server1\", \"Server_1\", \"Main Server\", \"192.168.0.3\")),
    set((\"Server_1\", \"VIP Server\", \"Main Server\")),
    set((\"Server_2\", \"192.168.0.4\")),
    set((\"192.168.0.3\", \"192.168.0.5\")),
    set((\"Server_2\", \"Backup\"))]

b = {}
c = set()
for s in a:
    full_s = s.copy()
    for d in s:
        if b.get(d):
            full_s.update(b[d])
    for d in full_s:
        b[d] = full_s
    c.add(frozenset(full_s))

for k,v in b.items():
    fsv = frozenset(v)
    if fsv in c:
        print(list(fsv))
        c.remove(fsv)
    

要回复问题请先登录注册