Java 要从另一个列表中存在的列表中删除某些元素吗

Java 要从另一个列表中存在的列表中删除某些元素吗,java,Java,我有一张单子 listA=[679,890,907,780,5230,781] 并希望删除其他文件中存在的某些元素 listB=[907,5230] 最小时间复杂度 我可以通过使用两个“for循环”来解决这个问题,这意味着O(n2)时间复杂度,但是我想把这个复杂度降低到O(nlog(n))或O(n)? 有可能吗?您可以通过以下方式实现这一点 对第二个列表进行排序(您可以对列表中的任何一个进行排序。这里我对第二个列表进行了排序)。在第一个数组中循环之后,对于第一个数组中的每个元素,在第二个数组

我有一张单子

listA=[679,890,907,780,5230,781]
并希望删除其他文件中存在的某些元素

listB=[907,5230]
最小时间复杂度

我可以通过使用两个“for循环”来解决这个问题,这意味着O(n2)时间复杂度,但是我想把这个复杂度降低到O(nlog(n))或O(n)?
有可能吗?

您可以通过以下方式实现这一点

对第二个列表进行排序(您可以对列表中的任何一个进行排序。这里我对第二个列表进行了排序)。在第一个数组中循环之后,对于第一个数组中的每个元素,在第二个数组中进行二进制搜索

您可以使用Collections.sort()方法对列表进行排序

总复杂性:-

对于排序:-O(mLogm)其中m是第二个数组的大小。我只对第二个数组进行了排序


对于删除:-O(nLogm)

您可以通过以下方式实现

对第二个列表进行排序(您可以对列表中的任何一个进行排序。这里我对第二个列表进行了排序)。在第一个数组中循环之后,对于第一个数组中的每个元素,在第二个数组中进行二进制搜索

您可以使用Collections.sort()方法对列表进行排序

总复杂性:-

对于排序:-O(mLogm)其中m是第二个数组的大小。我只对第二个数组进行了排序


用于删除:-O(nLogm)如果对其中一个列表进行了排序,则可以删除。假设列表A已排序,而列表B未排序,且维度分别为
M
N
,则从列表A中删除所有列表B元素的最小时间复杂度为
O((N+M)*log(M))
。实现这一点的方法是通过二进制搜索-列表A中元素的每次查找都需要
O(log(M))
时间,并且有
N
查找(列表B中的每个元素一次)。由于排序A需要花费
O(M*log(M))
时间,因此对大型列表进行排序然后删除所有元素更为有效,总时间复杂度
O((N+M)*log(M))

另一方面,如果没有排序列表,只需使用,在本例中,它的时间复杂度为O(M*N)
。这种时间复杂性的原因是
removeAll
执行(默认情况下)类似于以下伪代码的操作:

public boolean removeAll(Collection<?> other)
    for each elem in this list
        if other contains elem
            remove elem from this list
对于b的坏值,构建
查找
的时间可能会占用时间
O(N*log(N))
,如图所示(请参阅“病理分布键”)。在这之后,调用
removeAll
将花费
O(1)
for
contains
over
M
迭代,花费
O(M)
时间执行。因此,这种方法的时间复杂度是O(M+N*log(N))

因此,这里有三种方法。一个提供时间复杂度
O((N+M)*log(M))
,另一个提供时间复杂度
O(M*N)
,最后一个提供时间复杂度
O(M+N*log(N))
。考虑到第一种方法和最后一种方法在时间复杂度上是相似的(因为即使对于大的数字,
log
往往也很小),我建议对于小的输入使用朴素的
O(M*N)
,对于中等大小的输入使用最简单的
O(M+N*log(N))
。当您的内存使用开始受到创建哈希集来存储B元素(非常大的输入)的影响时,我最终会切换到更复杂的
O((N+M)*log(M))
方法

您可以找到AbstractCollection.removeAll实现

编辑:

第一种方法对ArrayList不太有效——显然,从列表A的中间删除需要
O(M)
时间。相反,对列表B进行排序(
O(N*log(N))
),并遍历列表A,根据需要删除项目。这需要
O((M+N)*log(N))
时间,并且比使用ArrayList时得到的
O(M*N*log(M))
要好。不幸的是,此算法的“适当删除项”部分要求您创建数据以将未删除的元素存储在
O(M)
中,因为您无法访问列表A的内部数据数组。在这种情况下,最好使用哈希集方法。这是因为(1)
O((M+N)*log(N))
的时间复杂度实际上比HashSet方法的时间复杂度差,(2)新算法不节省内存。因此,只有当您有一个包含
O(1)
删除时间的列表(例如LinkedList)和大量数据时,才使用第一种方法。否则,使用removeAll。它更简单,通常更快,并得到库设计人员的支持(例如,ArrayList有一个
removeAll
实现,允许它使用可忽略不计的额外内存来花费线性时间而不是二次时间)。

如果对其中一个列表进行排序,这是可能的。假设列表A已排序,而列表B未排序,且维度分别为
M
N
,则从列表A中删除所有列表B元素的最小时间复杂度为
O((N+M)*log(M))
。实现这一点的方法是通过二进制搜索-列表A中元素的每次查找都需要
O(log(M))
时间,并且有
N
查找(列表B中的每个元素一次)。由于排序A需要花费
O(M*log(M))
时间,因此对大型列表进行排序然后删除所有元素更为有效,总时间复杂度
O((N+M)*log(M))

另一方面,如果没有排序列表,只需使用,在本例中,它的时间复杂度为O(M*N)
。这种时间复杂性的原因是
removeAll
执行(默认情况下)类似于以下伪代码的操作:

public boolean removeAll(Collection<?> other)
    for each elem in this list
        if other contains elem
            remove elem from this list
对于b的坏值,构造
查找
的时间可能会占用时间
O(N*log(N)