用于计算阵列中相同元素对的数量的有效算法

时间:2014-11-06 05:31:30

标签: c arrays performance algorithm

例如,

int num[] = {1, 5, 3, 12, 5, 1, 4};
int len = 7;
int count = 0;

(假设阵列中不超过2个相同的元素)
然后我会做

for(int i=0; i<len-1; i++) {
  for(int j=i+1; j<len; j++) {
    if(num[i] == num[j]) {
      count++;
    }
  }
}  

然后计数为2。

但是这种算法导致O(N ^ 2)的效率 有没有更有效的方法?
提前谢谢!

4 个答案:

答案 0 :(得分:5)

O(n log n)排序更快,请使用hash table。它的结构是线性的或O(n);每次插入时,当您遍历输入数组时,如果哈希表中已存在该键,则可以测试(具有常量O(1)成本) - ,“对”。当您找到此“匹配”案例时,您会增加一个计数器。一旦你完成了阵列,你的计数器会告诉你答案。

答案 1 :(得分:0)

你可以这样试试:

#define MAX 99999   // consider your array have largest elemnt < 99999 and >=0
    int main () {
    int num[] = {1, 5, 3, 12, 5, 1, 4,3};
    int len = 8;
    int count[MAX+1u] = {0};
    int i,pair=0;
    for( i=0;i<len;i++){
         count[num[i]]++;   // here count the frequecy of each number
    }
    for(i=0;i<MAX;i++){
     if(count[i]>1){               // if frequecy is > 1      
    printf("%d occurs %d times \n",i,count[i]);
    pair++;         // increment pair
    }

    }
    printf("%d pairs ",pair);   // print pair
       return 0;
    }

答案 2 :(得分:0)

基本上,核心思想保持不变:你必须计算输入数组中每个元素的出现次数。

关键问题是如何实施这一计数过程。您的解决方案完全有效,但正如您所感觉到的那样,它可以得到改进。 您收到一条评论建议对数组进行排序,然后对其执行扫描以计算对数:O(n.ln n)。

您也可以使用哈希表,如@AlexReynolds回答所示。但是你必须处理冲突,因为不同的整数可以散列到同一个密钥。为此,您可以为每个密钥使用一个存储桶。这个桶将存储散列到其键的每个整数,加上所述整数的出现次数。

如何实现这些存储桶:

  • 使用列表?如果你有一些碰撞,这就足够了。
  • 使用(如二进制堆):对数访问和插入,但是固定大小,如果发生太多冲突,您可能需要重新分配。如果您不低估碰撞次数,但如果高估它会增加内存使用量,这是很好的。
  • 使用平衡二进制树:对数查找和插入,但由于指针跟踪在“内部”进行而导致空间开销。但是在这里,你避免了引起的估计问题。

构建哈希表后,如果数组中出现每个元素,则必须对这些对进行计数。但是,您可以在填充数据结构时保留计数器 以避免执行此额外扫描。这很简单。以下是使用从数组中取出的元素 e 来更新表的基本操作:

  1. 哈希 e :我们收到一个哈希键 k
  2. 获取散列密钥的存储桶 k b
  3. 查看存储桶以查看 e 是否在那里:
    • 如果是这样:增加元素出现计数器。 如果计数器为2,则递增对计数器,如果计数器为3,则递减对计数器。
    • 如果不是:将元素添加到存储桶,并将出现计数器设置为1
  4. 获取 e 中输入数组中的下一个元素,然后重复,直到数组完全呈现为止。
  5. 在每个计数器更新上执行一个 if 语句比在最后执行简单检查更快?我不确定,请注意你可以测试两者。

    k 成为哈希表中的槽数。使用均匀分布的散列函数,您将获得每个插槽的 n / k 元素。这导致列表的n²/ k时间复杂度,即O(n²)...... 如果 k 接近 n 你非常接近线性时间。

    堆/树桶也是如此,除了最终你得到O(n.nn)渐近复杂度。如果k足够大,那么你将接近线性时间。

答案 3 :(得分:0)

你不能使用普通的哈希表。我使用了动态编程和哈希表。

您应该像这样设置哈希表:

[数组的值,重复次数,相同对的数量]

例如,我们可以在数组A = [3, 3, 3, 3, 3]上运行我的算法。

我们走过数组。对于A中的第一个数字,新行将插入哈希表

  3,0,0 /* A[i], the number of repetition of 3 so far (Rep[i]),
                    the number of identical pair so far ( Iden[i]). */

然后是A中的第二个3:

 3,1,1 

在A中的第三个3:

 3,2,3 

在A中获得第4名:

 3,3,6 

6是该数组中相同对的数量。一般来说,我们可以通过以下公式计算相同对的数量:

Iden [i] = Rep [i] + Iden [i-1]

这是C#中的代码示例:

     public static int solution(int[] A)
    {
         int identical = 0;
        Dictionary<int, KeyValuePair<int, int>> dic = new Dictionary<int, KeyValuePair<int, int>>(); /* A[i], the number of repetition of 3 so far (Rep[i]),
                    the number of identical pair so far ( Iden[i]). */
        for (int i = 0; i < A.Length; i++)
        {
            if (!dic.ContainsKey(A[i]))
                dic.Add(A[i], new KeyValuePair<int, int>(0,0));
            else
            { 
               KeyValuePair<int,int> valDic = dic[A[i]];

                KeyValuePair<int, int> newVal;
                if (valDic.Key < 1)
                    newVal = new KeyValuePair<int, int>(1, 1);
                else
                {
                    int preIdenticalPair = valDic.Value;
                    int preReptation = valDic.Key;
                    int newRepetation = ++preReptation;
                    int newIdenticalPair = preIdenticalPair + newRepetation;
                    newVal = new KeyValuePair<int, int>(newRepetation, newIdenticalPair);
                }

                dic[A[i]] = newVal;
            }
        }

        //summation of all identical pairs
        foreach (KeyValuePair<int, KeyValuePair<int, int>> pair in dic)
            identical += pair.Value.Value;
        return identical;
    }