这是一个CS人员用理论发光的练习。

想象一下,你有两个带元素的容器。文件夹,URL,文件,字符串,这没关系。

什么是计算添加和删除的AN算法?

注意:如果有很多方法可以解决此问题,请为每个答案发布一个,以便对其进行分析和投票。

编辑:所有答案都解决了4个容器的问题。是否可以只使用最初的2?

有帮助吗?

解决方案

假设您有两个独特项目列表,并且排序无关紧要,您可以将它们视为集合而不是列表

如果你想到一个维恩图,列表A作为一个圆圈而列表B作为另一个,那么这两个的交点就是常数池。

从A和B中移除此交叉点中的所有元素,并且A中剩余的任何内容都已删除,而B中剩余的任何内容都已添加。

所以,迭代A搜索B中的每个项目。如果找到它,将其从A和B中删除

然后A是已删除的事物列表,B是已添加的事物列表

我想......

[edit]好的,使用新的“仅2个容器”限制,同样仍然存在:

foreach( A ) { 
  if( eleA NOT IN B ) {
    DELETED
  }
}
foreach( B ) {
  if( eleB NOT IN A ) {
    ADDED
  }
}

然后你没有构建一个新的列表,或者破坏你的旧列表......但是它会花费更长的时间,就像前面的例子一样,你可以循环遍历较短的列表并从较长的列表中删除元素。在这里你需要做两个列表

我认为我的第一个解决方案没有使用4个容器,只是销毁了两个; - )

其他提示

我有一段时间没有这样做,但我相信算法是这样的......

sort left-list and right-list
adds = {}
deletes = {}
get first right-item from right-list
get first left-item from left-list
while (either list has items)
  if left-item < right-item or right-list is empty
    add left-item to deletes
    get new left-item from left-list
  else if left-item > right-item or left-list is empty
    add right-item to adds
    get new right-item from right-list
  else
    get new right-item from right-list
    get new left-item from left-list

关于右侧列表与左侧列表的关系,删除包含已删除的项目,添加现在包含新项目。

乔说。并且,如果列表太大而无法放入内存,请使用外部文件排序实用程序或合并排序。

缺少信息:如何定义添加/删除?例如。如果列表(A和B)在服务器A和服务器B上显示相同的目录,则表示同步。如果我现在等待10天,再次生成列表并进行比较,如何判断是否已删除某些内容?我不能。我只能说服务器A上的文件在服务器B上找不到和/或反过来。是否因为文件已添加到服务器A(因此在B上找不到该文件)或文件已在服务器B上删除(因此该文件在B 上找不到)是我只能通过列出文件名来确定一些东西。

对于我建议的解决方案,我假设您有一个名为OLD的列表和一个名为NEW的列表。在旧的但未在NEW上找到的所有内容都已删除。已添加在NEW上但未在OLD上找到的所有内容(例如,同一服务器上的同一目录的内容,但是已在不同日期创建列表)。

此外,我将假设没有重复。这意味着任何列表中的每个项目在以下意义上都是唯一的:如果我将此项目与列表中的任何其他项目进行比较(无论此比较如何工作),我总是可以说该项目是更小更大比我正在比较的那个,但从不相等。例如。在处理字符串时,我可以按字典顺序对它们进行比较,并且列表中的相同字符串永远不会两次。

在这种情况下,最简单的(不一定是最佳解决方案)是:

  1. 对OLD列表进行排序。例如。如果列表由字符串组成,则按字母顺序排序。排序是必要的,因为这意味着我可以使用二进制搜索来快速查找列表中的对象,假设它确实存在(或者要快速确定,它根本不存在于列表中)。如果列表未排序,则查找对象的复杂度为O(n)(我需要查看列表中的每个项目)。如果对列表进行排序,则复杂度仅为O(log n),因为在每次尝试匹配列表中的项目之后,我总是可以排除列表中50%的项目不匹配。即使列表有100个项目,找到一个项目(或检测到该项目不在列表中)最多需要7个测试(或者它是8个?无论如何,远远少于100个)。 新列表无需排序。

  2. 现在我们执行列表删除。对于新列表中的每个项目,尝试在OLD列表中找到此项目(使用二进制搜索)。如果找到该项目,请从旧列表中删除此项目,然后 将其从新列表中删除。这也意味着消除过程中列表越小越好,因此查找将变得越来越快。由于从列表中删除项目对列表的正确排序顺序没有影响,因此无需在淘汰阶段使用OLD列表。

  3. 在淘汰结束时,两个列表可能都是空的,在这种情况下它们是相等的。如果它们不为空,则OLD列表中的所有项目都是新列表中缺少的项目(否则我们已将其删除),因此这些是已删除的项目。仍在新列表中的所有项目都是不在OLD列表中的项目(否则,我们已将其删除),因此这些是添加的项目

列表中的对象是否“唯一”?在这种情况下,我首先构建两个映射(散列图),然后扫描列表并查找映射中的每个对象。

map1
map2
removedElements
addedElements

list1.each |item|
{
    map1.add(item)
}
list2.each |item|
{
    map2.add(item)
}
list1.each |item|
{
    removedElements.add(item) unless map2.contains?(item)
}
list2.each |item|
{
    addedElements.add(item) unless map1.contains?(item)
}

对于混合Ruby和Java的可怕的元语言抱歉:-P

最后 removedElements 将包含属于list1的元素,但不包含list2, addedElements 将包含属于list2的元素。

整个操作的成本是O(4 * N),因为地图/字典中的查找可以被认为是恒定的。另一方面,线性/二进制搜索列表中的每个元素将使O(N ^ 2)。

编辑:第二个想法是将最后一个检查移到第二个循环中,你可以删除其中一个循环...但那很丑......:)

list1.each |item|
{
    map1.add(item)
}
list2.each |item|
{
    map2.add(item)
    addedElements.add(item) unless map1.contains?(item)
}
list1.each |item|
{
    removedElements.add(item) unless map2.contains?(item)
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top