如何比较时间复杂度小于 O(n^2) 的两个数组中的每个元素

Posted

技术标签:

【中文标题】如何比较时间复杂度小于 O(n^2) 的两个数组中的每个元素【英文标题】:How to compare each element in two arrays with time complexity less than O(n^2) 【发布时间】:2019-04-07 16:33:30 【问题描述】:

假设我们有两个数组 A[n] 和 b[n],目标是比较 A 中的每个元素和 B 中的元素。然后返回一个列表 result[n],它记录了 A 中每个元素的个数大于 B 中的元素。

例如,

A = [38, 24, 43, 3],B = [9, 82, 10, 11]

由于 38 大于 9、10 和 11,所以 result[0] 为 3。 那么结果就是 [3, 3, 3, 0]。

如果能提供一些伪代码就最好了。

谢谢。

【问题讨论】:

如果你能提供一些你的想法会很棒。 如果它们都已排序,则很容易遍历 O(n) 中的列表并找到 B 中的索引,在该索引处元素变得大于 A 中的每个元素。 您能否提供一些您遇到此问题的链接?比如 leetcode、geeksforgeeks、hackerrank 等 【参考方案1】:

您可以以 O(nlogn) 复杂度执行上述算法,其中 n 是问题中给出的数组 A 和数组 B 的长度。

算法

1. Sort both the arrays A and B, this will take O(nlogn) time complexity.
2. Take two pointers i and j, initialize both of them to 0. we will use i for array A and j for B.
3. Create a result array res of size n.
4. Start a while loop 
   while(i<n && j<n) 
     if(A[i] > B[j]) 
       j++;
      else 
       res[i] = j+1;
       i++;
     
   
5. while(i<n) 
     res[i] = n;
   
   This step is for the case where all elements in A are bigger than all elements in B.

最后,res 数组将准备好答案。

总体时间复杂度 - O(nlogn)

希望这会有所帮助!

【讨论】:

这简直太棒了!!太感谢了。顺便说一句,第 4 步循环的最差运行时间应该是 O(n),对吧? @Zack 这给出了错误的值,如果 A 中的任何值都大于 B 中的所有值,那么您会得到不完整的结果。试试我的答案。 @Richardissimo 非常感谢您指出我程序中的错误,我已修复它。我忘了涵盖这个案例,在提供答案时,我的主要目标是涵盖算法的主要逻辑。 即使在编辑之后,它仍然不正确,令人沮丧的是,它被标记为已接受的答案,并且当我的答案正确而没有正确时,它已被投票赞成。 @Richardissimo 我错过了什么情况,我们可以改进答案。【参考方案2】:

这两个列表都需要按升序排序才能正常工作。

分拣成本O(log n)。而大 O 算术意味着做两次仍然是O(n log n)。我将假设它们已经排序。下面的剩余工作不会影响 big-O 成本。

有一个名为indexBB 数组的索引,值为零(我的伪代码将使用从零开始的索引)。而indexA 代表A 也从零开始。

indexA=0
For each indexB from 0 to B.Length-1
    While indexA < A.Length and the value at `A[indexA]` is less than or equal to the value at `B[indexB]`
        Set the `result[indexA]` to be `indexB`
        Increment `indexA`
    Endwhile
Endfor

之后,result 中从indexA 开始的所有剩余项都大于B 中的所有项,因此将其余项设置为B.Length


在发布我的原始答案 2 年后编辑,添加: 实际 C# 代码以反映上述伪代码。我相信下面的代码是O(n),与首先对数组进行排序的成本相比,这可以忽略不计(在大O 方面),所以总成本仍然是O(n log n)

            // Note: I am simulating pre-sorted arrays, which costs "O(n log n)"...
            // The reason for adding this sample code is to help clarify the cost of the
            // remaining work (after the sorts) by showing real code, to avoid any
            // ambiguity from the pseudocode, even though that's what the OP asked for
            var A = new[]  3, 24, 38, 43 ;
            var B = new[]  9, 10, 11, 82 ;
            var result = new int[4];

            int indexA = 0;
            for (int indexB = 0; indexB < B.Length; indexB++)
            
                while (indexA < A.Length && A[indexA] <= B[indexB])
                
                    result[indexA] = indexB;
                    indexA++;
                
            

            while (indexA < A.Length)
            
                result[indexA] = B.Length;
                indexA++;
            

            Console.WriteLine(string.Join(", ", result));

【讨论】:

在这里我可以看到一个嵌套的 while 在每个 fo 中。复杂度为 O(n^2) @jithil 它没有遍历每个循环内的所有项目。您需要实际查看逻辑。尝试关注indexA 的情况。 但是,在 Big O 中,O(n*(n/2)) => O(n^2) 因为常量将被排除在外。 @jithil 你从哪里得到n/2,你为什么要把它乘以n? “for”循环是n,其中的“while”循环独立于包含它的for循环,也是n。所以它会执行n+n 次的工作,也就是O(2*n),相当于O(n) @jithil 请查看代码并尝试运行它。向其中添加您自己的断点或消息。最坏的情况是n+n。事实上,它总是会这样做的次数。有 4 个项目,它做了 8 件工作,而不是 16 个。如果 A 和 B 各有 1000 个项目,它会做 2000 件工作,而不是 100 万件。

以上是关于如何比较时间复杂度小于 O(n^2) 的两个数组中的每个元素的主要内容,如果未能解决你的问题,请参考以下文章

[LeetCode]Minimum Size Subarray Sum

数组中的逆序对

数组中的逆序对与归并中的分治思想

快排题目

数组中的逆序对

给定数组和一个常量,从数组中找到两个数之和等于常量,如何做最快