给定一个整数数组,找到第一个唯一的整数

时间:2011-10-26 18:42:50

标签: c++ c algorithm sorting map

给定一个整数数组,找到第一个唯一的整数。

我的解决方案:使用std::map

将整数(数字作为键,其索引作为值)逐一放入(O(n^2 lgn)),如果有重复,则在将所有数字放入地图后,从地图(O(lg n))中删除条目,迭代地图并找到索引为O(n)最小的密钥。

O(n^2 lgn)因为地图需要进行排序。

效率不高。

其他更好的解决方案?

6 个答案:

答案 0 :(得分:11)

我认为以下是最佳解决方案,至少基于时间/空间复杂性:

第1步: 将整数存储在哈希映射中,该映射将整数保存为键,并将其显示为值的计数次数。这通常是 O(n)操作,并且哈希表中元素的插入/更新平均应该是恒定时间。如果发现整数出现的次数超过两次,则实际上不必进一步增加使用次数(如果您不想这样做)。

第2步: 对整数执行第二次传递。在哈希映射中查找每个,并且外观计数为1的第一个是您要查找的那个(即,第一个单个出现的整数)。这也是 O(n),使整个过程 O(n)

针对特殊情况的一些可能的优化:

优化A:可以使用简单数组而不是哈希表。即使在最坏的情况下,这也可以保证O(1)计算特定整数的出现次数以及查看其出现次数。此外,这增强了实时性能,因为不需要执行散列算法。由于可能较差的引用局部性(即,较大的稀疏表与具有合理的加载因子的哈希表实现)可能存在命中。但是,这将是针对整数排序的非常特殊情况,并且可以通过散列表的散列函数来缓解,该散列函数基于传入的整数生成伪随机桶放置(即,开始的参考的不良位置)。

数组中的每个字节表示由该字节的索引表示的整数的计数(最多255)。只有当最低整数和最高值(即有效整数域的基数)之间的差足够小以使该数组适合存储器时,这才是可能的。特定整数数组中的索引将是其值减去数据集中存在的最小整数。

例如,在具有64位操作系统的现代硬件上,可以想象可以分配4GB阵列,它可以处理整个32位整数域。可以想象更大的阵列具有足够的内存。

在处理之前必须知道最小和最大的整数,或者使用minmax算法通过数据进行另一次线性传递,以找出这些信息。

优化B:您可以进一步优化优化A ,每个整数最多使用2位(一位表示存在,另一位表示多重性)。这将允许每个字节表示四个整数,扩展数组实现以处理给定量的可用内存的更大的整数域。可以在这里播放更多位游戏来进一步压缩表示,但它们只支持特殊情况下的数据,因此不能推荐用于大多数情况。

答案 1 :(得分:1)

这一切都没有理由。只需使用2 for-loops&变量会给你一个简单的O(n^2)算法。

如果您在使用哈希映射时遇到了麻烦,那么@Micheal Goldshteyn建议也可能

更新:我知道这个问题是1岁。但正在查看我回答的问题,并发现了这一点。认为有一个比使用哈希表更好的解决方案。

当我们说独特时,我们会有一个模式。例如:[5,5,66,66,7,1,1,77]。在这个让我们有移动窗口3.首先考虑(5,5,66)。我们可以轻松地建立。这里有重复。所以我们得到(5,66,66),将窗口移动1个元素。同样在这里。转到下一个(66,66,7)。再次重复这里。接下来(66,7,1)。这里没有重复!取中间元素,因为这必须是集合中的第一个唯一元素。左边的元素属于dup,所以可以1.因此7是第一个独特的元素。

空间:O(1) 时间:O(n)* O(m ^ 2)= O(n)*9≈O(n)

答案 2 :(得分:0)

插入地图时,O(log n)不是O(n log n),因此插入n密钥将为n log n。使用set也更好。

答案 3 :(得分:0)

虽然它是O(n ^ 2),但是下面的系数很小,在缓存上也不算太差,并使用快速的memmem()

 for(int x=0;x<len-1;x++)
     if(memmem(&array[x+1], sizeof(int)*(len-(x+1)), array[x], sizeof(int))==NULL &&
        memmem(&array[x+1], sizeof(int)*(x-1), array[x], sizeof(int))==NULL)
            return array[x];

答案 4 :(得分:0)

public static string firstUnique(int[] input)  
{
    int size = input.Length;
    bool[] dupIndex = new bool[size];
    for (int i = 0; i < size; ++i) 
    {
        if (dupIndex[i]) 
        {
            continue;
        } 
        else if (i == size - 1) 
        {
            return input[i].ToString();
        }
        for (int j = i + 1; j < size; ++j) 
        {
            if (input[i]==input[j]) 
            {
                dupIndex[j] = true;
                break;
            } 
            else if (j == size - 1)
            {
                return input[i].ToString();
            }
        }
    }
    return "No unique element";
}

答案 5 :(得分:0)

@ user3612419

  Solution given you is good with some what close to O(N*N2) but further optimization in same code is possible I just added two-3 lines that you missed.



public static string firstUnique(int[] input)  
{
  int size = input.Length;
  bool[] dupIndex = new bool[size];
  for (int i = 0; i < size; ++i) 
  {
     if (dupIndex[i]) 
    {
        continue;
    } 
    else if (i == size - 1) 
    {
        return input[i].ToString();
    }
    for (int j = i + 1; j < size; ++j) 
    {
  if(dupIndex[j]==true)
  {
 continue;
 }
        if (input[i]==input[j]) 
        {
            dupIndex[j] = true;
    dupIndex[i] = true;
            break;
        } 
        else if (j == size - 1)
        {
            return input[i].ToString();
         }
     } 
  }
return "No unique element";
 }