【问题标题】:Count number of identical pairs计算相同对的数量
【发布时间】:2015-06-14 20:45:26
【问题描述】:

数组中相同的一对是 2 个索引 p,q 使得

0<=p<q<Narray[p]=array[q] 其中N 是数组的长度。

给定一个未排序的数组,找出数组中相同的对数。

我的解决方案是按值对数组进行排序, 跟踪索引。

然后对于排序数组中的每个索引p,计算所有q<N,这样和

sortedarray[p].index < sortedarray[q].index and 
sortedarray[p] = sortedarray[q]  

这是正确的方法吗?我认为复杂性是

O(N log N) for sorting based on value  +

O(N^2) for counting the newsorted array that satisfies the condition. 

这意味着我仍在查看O(N^2)。有没有更好的办法?

另一个想法是,对于每个 P 二分查找满足条件的所有 Q 的排序数组。这不会将第二部分的复杂性降低到O(Nlog(N))

这是我的第二部分代码

    for(int i=0;i<N;i++){

                    int j=i+1;

            while( j<N && sortedArray[j].index > sortedArray[i].index &&
                   sortedArray[j].item == sortedArray[i].item){

                        inversion++;
                        j++;
            }
      }
   return inversion;

@Edit:我想,我把第二部分的复杂性误认为是O(N^2)

在 while 循环中的每次迭代中,不会重新扫描索引 0-i 中的元素,扫描排序数组以计算反转需要线性时间。因此,总复杂度为

O(NlogN) 用于排序,O(N) 用于排序数组中的线性扫描计数。

【问题讨论】:

  • 由于排序会将相等的值放在一起,因此您无需检查所有q,只需检查p 附近的那些。如果您使用稳定的排序算法,您甚至不需要执行第一次测试。
  • 正确,我需要检查 p 附近的值,对于 0

  • 数组已排序这一事实意味着您可以一次扫描它。所以不是 O(n^2) 而是 O(n)。作为一个反例,插入排序是 O(n^2),因为对于每个元素,它必须扫描整个数组。
  • @mdm,能否请您参考我的第二部分代码,可能是我错过了您的观点,但我仍然觉得第二部分应该具有二次时间复杂度。
  • @SREEPRASADGOVINDANKUTTY 有一个平方数的对,但您可以在 O(n) 中计算它

标签: algorithm sorting


【解决方案1】:

我一直在考虑这个......我认为如果你将== 条件“嵌入”到你的排序算法中,那么复杂度仍然是 O(n lg n)。

【讨论】:

    【解决方案2】:

    如果您可以分配更多内存,您可以获得一些收益。

    您可以通过使用哈希表来访问O(n),该哈希表将数组中的任何值映射到一个计数器,该计数器指示您看到该值的频率。

    如果允许值的数量是整数并且在有限的范围内,您可以直接使用数组而不是哈希表。价值指数ii 本身。在这种情况下,复杂度将是O(n+m),其中m 是允许值的数量(因为您必须首先将数组中的所有条目设置为0,然后查看所有数组条目以计算对数)。

    这两种方法都会为您提供数组中每个值的相同值的数量。我们称这个数字nv_i 为值i 在数组中出现的次数。那么值i的对数为:(nv_i)*(nv_i-1)/2

    你可以配对:

    1st  i with nv_i-1 others
    2nd  i with nv_i-2 others
    ...
    last i with 0
    

    还有(nv_i-1)+(nv_i-2)+...+0 = (nv_i)*(nv_i-1)/2

    【讨论】:

    • 我们是否需要另一个哈希映射,不会线性扫描给我满足条件的索引计数。请参考我的代码和 TIm 和 mdm 的 cmets
    • @SREEPRASADGOVINDANKUTTY 如果对数组进行排序,则不需要哈希图。您可以遍历数组并计算nv_i。但是 hashmap 会给你所有的nv_i 而无需排序。因此,整个算法从 O(n*log(n)) 变为 O(n)
    • 你是如何更新计数器的?由于指标和值的条件可能不满足,因此不能是值被视为频率的频率。
    • @SREEPRASADGOVINDANKUTTY 是的,nv_i 就是你所说的频率。什么条件不能满足?请注意,值的特定索引与计算不同对的数量无关。您只需要知道给定长度nv_i 的值序列i 的存在。
    【解决方案3】:

    正如 Tim 在他的回复中指出的那样,在排序数组中查找对的复杂性是 O(n) 而不是 O(n^2)

    要让自己相信这一点,请考虑一个典型的 O(n^2) 算法:Insertion Sort

    可以在here找到一个动画示例。

    正如你在 gif 中看到的,这个算法之所以是二次的,是因为对于每个元素,它必须检查整个数组以确保这些元素必须去哪里(这 包括 数组中的前一个元素!)。

    另一方面,在您的情况下,您有一个有序数组:例如[0,1,3,3,6,7,7,9,10,10]

    在这种情况下,您将从头开始(成对)扫描,并且(因为数组是有序的)您知道一旦扫描了一个元素并且您的指针继续进行,就没有任何理由重新扫描未来的以前的元素,否则你一开始就不会继续。

    因此,您只扫描整个数组一次:O(n)

    【讨论】:

    • 这意味着我把第二部分的代码复杂度误认为是 O(N^2)。由于我的索引“j”总是大于索引“i”,因此不会重新扫描 0-i 的元素,复杂度实际上是 O(N) 。正确吗?
    • @SREEPRASADGOVINDANKUTTY 正确!
    【解决方案4】:

    你是部分正确的。通过合并排序或堆排序对数组进行排序将采用O(n lg n)。但是,一旦对数组进行了排序,您就可以通过一次遍历来找到所有相同的对。此单遍是O(n) 操作。所以总的复杂度是:

    O(n lg n + n) = O(n lg n)

    【讨论】:

    • 我认为单次传递不会给出所有值,它会给我计算 sortedarray 中满足条件的所有顺序值。
    • 在这个数组中找到相同的对有多难:[1, 5, 7, 7, 10, 13, 13, 20]
    • 蒂姆,你能否参考我的代码,我可能错过了你的观点,但我看不到第二部分的线性时间成本不变。
    • @SREEPRASADGOVINDANKUTTY 对数组进行排序后,您可以计算每个值在O(n) 中的数组中出现的次数,因为相等的值将是连续的。您可以轻松计算对数。看我的回答。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多