来自两个排序数组的最大对数

Posted

技术标签:

【中文标题】来自两个排序数组的最大对数【英文标题】:Maximum number of pairs from two sorted arrays 【发布时间】:2011-10-31 17:13:12 【问题描述】:

这不是原始问题。我有一个复杂的问题,现在简化为:

有两个排序数组,AB,分别带有 mn 元素,m = \Theta(n)o(mn) 时间运行的算法能否找到最大对数,使得A[i]-B[j] <= T 其中 T 是某个常数?如何才能做到这一点?

编辑:

    这些对应该是不相交的,即一个元素最多只能选择一次。

    算法应该在 little-o(mn) 中运行,这意味着在 mn 时间内运行的解决方案是不可接受的。

    是否也可以找到我们选择的对?

澄清:

如果数组是a_1, a_2, ..., a_mb_1, b_2, ..., b_n,我需要找到对(a_i, b_j) 这样|a_i - b_j| <= T。不允许多次选择一个元素。我们如何最大化给定数组的对数?

【问题讨论】:

以前从未见过 little-O:en.wikipedia.org/wiki/…。 Wiki 说o(mn) 意味着复杂性由mn 主导,这意味着mn 时间 可以接受的,m+n 可以接受的。请澄清。 @MooingDuck:不,右边有一个 epsilon 因子 - 这意味着它必须比 mn 运行。跨度> @AasmundEldhuset:我重读了这篇文章。我又错了。你是对的。 @MooingDuck 你能详细说明怎么做吗? 没关系,新的说明有一个绝对值,这意味着这个页面上的每个答案(截至目前)都是不正确的。 【参考方案1】:

更新 2:

更新的问题(仅使用任一数组中的元素一次,获取对,并且值的绝对差必须低于T)可能可以在O(n + m)中完成 时间。我还没有充分考虑下面的算法来决定它是否总是能获得最大的对数,但在大多数情况下应该:

int i = 0;
int j = 0; 

while(i < A.length)
    while(j < B.length)
        if(A[i]-B[j] <= T)
            if(A[i]-B[j] >= -1 * T)
                addPair(i, j);
                j++;//don't consider this value the next time
            
            break;
         
        j++;
    
    i++;

【讨论】:

这可以从 B 中多次选择一个元素。此外,不能保证它会选择最大的对集合。 问题的最新更新说|a_i - b_j| &lt;= T,添加了一个绝对值。 @PulkitGoyal:实际上,因为 i 和 j 都不会减少,所以它永远不会多次使用 AB 中的任何元素。 @MooingDuck 啊!抱歉,是我的错。但它仍然不适用于差异的绝对值。例如,考虑以下数组:20,3035,70T=10。该算法不会选择任何对。但是,最好选择 (30,35) 对。 @PulkitGoyal:我想知道我怎么从来没有注意到这段代码中的错误。没错,正确的答案稍微复杂一些。【参考方案2】:

O(n lg n) = O(m lg m)中:从A的元素创建平衡二叉搜索树,并在每个节点中存储元素的索引和元素值。对于B 的每个元素,搜索小于或等于B[j] + T 的最大值。这个数字的索引会告诉你有多少数字小于或等于这个数字。

【讨论】:

“创建平衡的二叉搜索树” - 这本身不需要时间吗? 我正在寻找不同的对,这意味着一个数字一旦被选中就不能再次被选中。 @GigaWatt:是的,但只有O(n lg n) @AasmundEldhuset 我不明白这将如何产生正确数量的对,因为它可以多次使用一个元素。【参考方案3】:

如果您想要匹配|A[i]-B[j]| &lt;= T 的对数,其中每个A[i]B[j] 在所有对中仅使用一次:

int lastB = 0;
int result=0;
for(int a = 0; a<A.size(); ++a) 
    const int minB = A[a] - T;  
    while(lastB<B.size() && B[lastB] < minB)
        ++lastB;
    const int maxB = A[a] + T;
    if (lastB<B.size() && B[lastB] > minB) 
        ++lastB;
        ++result;
    

return result;

此算法扫描B 中的最小范围,并确保B 中的任何元素都不会被使用两次。

【讨论】:

您的解决方案总是找到我可以使用 A_max 作为第一个元素获得的最大对数。但我需要元素是不同的。这意味着一旦你从一个数组中选择了一个元素,你就不能再选择它了。 由于所有其他元素都小于A_max,并且结果我从不返回超过A_max,因此您会发现无论如何这都会返回正确的数字。 我看不出它如何返回正确的结果。例如考虑以下数组:1, 2, 3, 1000999, 1000, 1001, 1002 以及阈值 5。如果我正确理解您的算法,它将返回对数为 4,而这里只有一对是可能的。 它将返回 4,原始问题有 4 个。 (1,999) (2,1000) (3,1001) (1000,1002) 等式是A[i]-B[j] &lt;= T2-1000&lt;=5 绝对正确。我刚刚注意到你的编辑 now 显示了一个绝对值,在这种情况下这个算法是有缺陷的。然后使用 Briguy37 的答案,它是下一个最快的。 @PulkitGoyal:在发现 Briguy37 有一个(主要)错误后,我用他的算法的固定版本替换了我的答案。

以上是关于来自两个排序数组的最大对数的主要内容,如果未能解决你的问题,请参考以下文章

Leetcode——数组中最大数对和的最小值

ava对数组元素排序的三种方式

给定一个数组,求如果排序后,相邻两个元素的最大差值,要求时间复杂度为O(N)

数组628. 三个数的最大乘积

2021-07-30:两个有序数组间相加和的Topk问题。给定两个有序数组arr1和arr2,再给定一个整数k,返回来自arr1和arr2的两个数相加和最大的前k个,两个数必须分别来自两个数组。按照降

二分数组差值最大