如何找到第一个非重复元素?

时间:2011-08-15 09:23:12

标签: c++ algorithm bit-manipulation

如何在数组中找到第一个非重复元素。 假设您只能为阵列的每个元素使用1位,并且时间复杂度应为O(n),其中n是数组的长度。 请确保我以某种方式对内存要求施加约束。也有可能的是,每个字符串元素只需要一个额外的位就可以完成。如果可能,请告诉我吗?

4 个答案:

答案 0 :(得分:3)

我想说没有基于比较的算法,可以在O(n)中完成。因为你必须将数组的第一个元素与所有其他元素进行比较,第二个除了第一个之外的所有元素,第三个除了第一个之外的全部= Sum i = O(n ^ 2)。

(但这并不一定意味着没有更快的算法,请参阅排序:如果你是基于比较的话,有一个证据表明你不能比O(n log n)排序快 - 而且确实有一个更快:Bucket排序,可以在O(n)中完成。

编辑:在其他一条评论中,我谈到了哈希函数。我检查了一些关于它的事实,这里是hashmap方法的想法:

  • 明显的方法是(在伪代码中):

    for (i = 0; i < maxsize; i++)
        count[i] = 0;
    for (i = 0; i < maxsize; i++) {
       h = hash(A[i]);
       count[h]++;
    }
    first = -1;
    for (i = 0; i < maxsize; i++)
       if (count[i] == 0) {
          first = i;
          break;
       }
    }
    for (i = 0; hash(A[i]) != first; i++) ;
    printf("first unique: " + A[i]); 
    
  • 有一些警告:

    1. 如何获得hash。我做了一些关于完美哈希函数的研究。事实上,你可以在O(n)中生成一个。 (最小完美散列的最佳算法由George Havas等人 - 不确定这篇论文有多好,因为它声称为时间限制O(n)但是从非线性空间限制(这是计划)一个错误,我希望我不是唯一看到这个中的缺陷,但根据我所知道的所有理论计算机科学的时间是空间的上边界(因为你没有时间在更多的空间写))。但是我当他们说在O(n)中有可能时,请相信他们。

    2. 额外的空间 - 这里我没有看到解决方案。上面的论文引用了一些研究表明,你需要2.7位的完美哈希函数。使用额外的count数组(可以缩短为状态:空+ 1个元素+超过1个元素),每个元素需要2个额外的位(如果您认为可以以某种方式与上述2.7结合使用,则为1.58) ,总计达到5位。

答案 1 :(得分:1)

这里我只假设字符串是字符串,只包含小字母,这样我就可以使用一个整数(32位),这样就可以使用26个字母表,每个字母表占一位。之前我想过采用256个元素的数组,但总共会有256 * 32位。每个元素32位。但最后我发现如果没有一个变量,我将无法做到。所以解决方案是这样的,只有一个整数(32位)用于26个字母:

 int print_non_repeating(char* str)
 {
  int bitmap = 0, bitmap_check = 0;
  int length = strlen(str);
  for(int i=0;i<len;i++)
  {
   if(bitmap & 1<<(str[i] - 'a'))
     {
        bitmap_check = bitmap_check | ( 1 << (str[i] - 'a');
      }
   else 
      bitmap = bitmap | (1 << str[i] - 'a');
  }
  bitmap = bitmap ^ bitmap_check;
  i = 0;
  if(bitmap != 0)
  {
  while(!bitmap & (1<< (str[i])))
   i++;
  cout<<*(str+i);
   return 1;
  }
  else 
  return 0;
  }

答案 2 :(得分:0)

此代码查找第一个重复元素。还没想到如果在同一个for循环中,如果有可能找到非重复元素而不引入另一个(保持代码O(n))。其他答案建议冒泡排序为O(n ^ 2)

#include <iostream>
using namespace std;
#define max_size 10

int main()
{
    int numbers[max_size] = { 1, 2, 3, 4, 5, 1, 3, 4 ,2, 7};
    int table[max_size] = {0,0,0,0,0,0,0,0,0,0};
    int answer = 0, j=0;

  for (int i = 0; i < max_size; i++)
  {
    j = numbers[i] %max_size;
    table[j]++;
    if(table[j] >1)
    {
          answer = 1;
          break;
    }
 }
   std::cout << "answer = " << answer ;
}

答案 3 :(得分:0)

您可以尝试执行修改后的bucketsort,如下所示。但是,您需要知道传递给firstNonRepeat方法的数组中的最大值。所以这在O(n)处运行。 对于基于比较的方法,理论上最快(至少在排序方面)是O(n log n)。或者,您甚至可以使用基数排序的修改版本来实现此目的。

public class BucketSort{
    //maxVal is the max value in the array
    public int firstNonRepeat(int[] a, int maxVal){
        int [] bucket=new int[maxVal+1];

        for (int i=0; i<bucket.length; i++){
            bucket[i]=0;
        }

        for (int i=0; i<a.length; i++){
            if(bucket[a[i]] == 0) {
                bucket[a[i]]++;             
            } else {
                return bucket[a[i]];
            }
        }
    }
}