Java 两个数组中的第一个公共数,大小均为100万

Java 两个数组中的第一个公共数,大小均为100万,java,arrays,algorithm,Java,Arrays,Algorithm,我有两个非常大的整数数组,每个数组的大小大约为一百万。我必须找到两个数组中的第一个整数 我试着用一台电视机来做这件事 (1) 模拟遍历每个数组,并在集合中插入两个数组的元素 (2) 当集合拒绝接受时,这是第一个交点 int Solution(int A[], int B[]) { Set s = new HashSet(); for (int i = 0 ; ; i++) { if ( i < A.length ) {

我有两个非常大的整数数组,每个数组的大小大约为一百万。我必须找到两个数组中的第一个整数

我试着用一台电视机来做这件事

(1) 模拟遍历每个数组,并在集合中插入两个数组的元素

(2) 当集合拒绝接受时,这是第一个交点

int Solution(int A[], int B[])
{
    Set s = new HashSet();
    for (int i = 0 ; ; i++)
    {
        if ( i < A.length )
        {
            if( !s.Add(A[i]) )
                System.out.println(A[i]);
        }
        if ( i < B.length )
        {
            if( !s.Add(B[i]) )
                System.out.println(B[i]);
        }
    }
}
int解决方案(inta[],intb[]
{
Set s=新的HashSet();
对于(int i=0;i++)
{
如果(i
我们能否改进此解决方案以降低时间复杂性


谢谢

您可以使用最坏时间为
n log n
的合并排序,然后使用最坏情况为
log n
的二进制搜索来获得总最坏时间(很抱歉,有一段时间没有做这个计算,所以可能会关闭)
O(n log(log n^2))

它可以在
O(n+m)
时间(平均)和
O(n)
空间中完成(
n
是第一个数组的大小,
m
是第二个数组的大小)


内存消耗略有改善:

可以将其改进为
O(min{n,m})
空间,方法是首先检查哪个数组较小,如果第二个数组-执行与建议相同的算法,否则,将(元素,索引)对加载到map
(x,i)
,迭代第二个列表,并在匹配的位置找到最小的
i
,然后返回:

内存复杂度更高的方法的伪代码:

def secondSmaller(arr1,arr2):
    set = new empty hash set
    for each x in arr2:
        set.add(x)
    for each x in arr1 in ascending order:
        if set.contains(x):
            return x
    //if here, no duplicates
    return null
def firstSmaller(arr1,arr2):
    map = new empty hash map
    for each x in arr1 with index i:
        map.add(x,i)
    minimal = infinity
    minVal = null
    for each x in arr2:
         if set.contains(x):
         i = map.get(x)
         if i < minimal:
            minimal = i
            minVal = x
     return minVal
if arr1.size() > arr2.size():
     return secondSmaller(arr1,arr2)
else return firstSmaller(arr1,arr2)
def秒更小(arr1、arr2):
set=新的空哈希集
对于arr2中的每个x:
集合。添加(x)
对于arr1中的每个x,按升序排列:
如果设置。包含(x):
返回x
//如果在此处,则没有重复项
返回空
def FIRSTLOWER(arr1、arr2):
map=新的空哈希映射
对于索引为i的arr1中的每个x:
地图。添加(x,i)
极小=无穷大
minVal=null
对于arr2中的每个x:
如果设置。包含(x):
i=map.get(x)
如果我<最小值:
最小值=i
最小值=x
返回minVal
如果arr1.size()>arr2.size():
返回第二个较小的(arr1、arr2)
否则返回第一个较小的值(arr1、arr2)

相关线程:



作为旁注,这与的密切相关,我怀疑它能比这更有效,因为它的效率更低。

与注释相反,排序和二进制搜索不是最有效的

假设两个数组的大小都是
N
,则将填充一个哈希表,然后用于检测时间上的重复项

相反,排序需要时间
O(nlg(N))
,在最坏的情况下,后续的二进制搜索也需要时间
O(nlg(N))

无论如何,如果您的数据已经排序,或者由于某种原因可以便宜地排序(bucket sort?),请不要使用二进制搜索,这会导致
O(N Log(N))
,而是在
O(N)
中进行合并


此外,如果整数的范围是有限的,例如不超过25个有效位(如0到33554431),则使用位数组可能是有利的。它需要4MB的空间(就像你的百万整数一样),时间
O(N)
用于初始化和检测重复项,代码非常简单快速

A={1,2,3}
B={2,1,3}
1是数字,因为它出现在
A

这意味着在某些情况下,您的算法不会产生正确的答案。考虑这些数据:

A = {1, 2, 3, 4, 5, 6, 7}
B = {7, 2, 3, 4, 5, 6, 1}
您的算法将返回2而不是1,因为在第二次插入到两个集合后将检测到2,而您需要迭代
B
到最后才能检测到1

根据您的规范,一种为您提供正确解决方案的方法是将
B
的所有元素加载到一个哈希集中,然后迭代
a
,直到您在由
B
中的数字组成的集合中获得命中。这种方法是O(Na+Nb)

Set bSet=new HashSet();
对于(int n:B){
b设置添加(n);
}
对于(int n:A){
if(b集合包含(n)){
返回n;
}
}
//如果你在这里,数组没有共同的元素

对java 32位
int
s数组进行排序,或者更一般地说,任何固定大小的整数都可以在
O(N)
时间内使用基数排序完成。对两个数组进行排序并合并它们。您将在
O(N)
time中找到all通用数字


使用此算法找到的第一个数字是最小的公共数,这是两个数组公共的第一个数字的可能解释

数组
{1,2,3}
{2,1,3}
中的第一个公共数是什么?数组是否已排序?如果是这样的话,我会想到二进制搜索。如果我正确地记住了我的算法,这只是O(n),或者在这种情况下是O(1000000)。也许你可以做一个非线性时间排序,然后运行一个二进制文件search@RyanJ偷了我的主意哈哈!但是,是的,我同意排序和二进制搜索对于降低时间复杂度非常有效。没有数组是不排序的,对于a{1,2,3}B{2,1,3}1是数字,因为它首先出现在a中。这比O(n)好吗?我想数学可以归结为
n log(n)+log(n)=log(n^(n+1))
@RyanJ谢谢!忘记了执行此操作的确切方法,已经有一段时间不必计算复杂度了。@hatchet我记得log函数通常比n函数增长得慢。@jgr208:你说得对<代码>n
的增长速度快于
日志n
。但是,
n*log n
的增长速度比
n
快。另外,如果您对一个数组进行合并排序,然后对另一个数组的每个元素进行二进制搜索,那么
A = {1, 2, 3, 4, 5, 6, 7}
B = {7, 2, 3, 4, 5, 6, 1}
Set<Integer> bSet = new HashSet<Integer>();
for (int n : B) {
    bSet.add(n);
}
for (int n : A) {
    if (bSet.contains(n)) {
        return n;
    }
}
// If you get here, arrays have no elements in common