唯一元素数组的最小间隔

时间:2012-09-03 05:12:53

标签: algorithm data-structures

如何找到整数数组的最小间隔,其中该数组的所有唯一元素 存在 。 例如我的阵列是:1 1 1 2 3 1 1 4 3 3 3 2 1 2 2 4 1 最小间隔是从索引3到索引7。 我正在寻找O(nlogn)或更少(n <= 100000)

的算法

1 个答案:

答案 0 :(得分:6)

策略从结束到开始迭代,记住你上次看到每个整数的时间。例如。在中间的某个地方,你最后在索引15处看到1,在索引20处看到2,在索引17处看到3。间隔长度是您上次看到的最大索引减去当前索引。

要轻松找到最大索引,您应该使用自平衡二叉搜索树(BST),因为它具有O(log n)插入和删除时间,以及最大索引的常量查找时间。

例如,如果您必须更新上次看到1的索引,则删除当前最后看到的索引(15),然后插入新的最后一个索引。

通过使用每个整数类型允许的所有结束索引更新自平衡BST,我们可以选择最大的,并说我们可以在那里结束。

确切的代码取决于输入的定义方式(例如,你是否知道所有整数是什么,即你知道数组中存在1到4之间的所有整数,那么代码就被简化了。)

迭代为O(n),BST为O(log n)。总体而言是O(n log n)


实施细则

实现这需要一些工作。

初​​始化:

  • 每个起始索引的间隔长度。
  • 您上次看到某个整数时的数组。 (如果您不知道数组中可能存在哪些整数,而不是使用普通数组,请使用关联数组(例如,C ++中的map<>)。)
  • 类似于队列的优先级类型,其中队列的顶部是其中的最大整数。您需要能够轻松地从中删除内容,因此请使用自平衡二叉搜索树

现在在循环内部(从输入数组的末尾到输入数组的开始循环索引),

  • 您可以为此特定索引更新上次看到的数组。

    只需检查您看到的整数,并更新索引上次看到的数组中的条目。

  • 在上次看到的数组中使用之前和之后,更新BST(删除旧的结束索引,添加新索引)

  • 根据所需的最大结束索引(来自BST)更新此起始索引的间隔长度。

  • 如果你看到一个你以前没见过的整数,那么启动索引高于这个索引的所有区间长度都会无效(或者只是避免更新区间长度,直到所有整数都被看到至少一次)。


C ++代码实现

  • 假设在输入数组中找到所有整数0-(k-1)
  • 免责声明:未经测试
  • 忽略#includemain功能

代码:

int n=10,k=3;
int input[n]=?;
unsigned int interval[n];
for (int i=0;i<n;i++) interval[i]=-1; // initialize interval to very large number
int lastseen[k];
for (int i=0;i<k;i++) lastseen[i]=-1; // initialize lastseen
multiset<int> pq;

for (int i=n-1;i>=0;i--) {
  if (lastseen[input[i]] != -1) // if lastseen[] already has index
    pq.erase(pq.find(lastseen[input[i]])); // erase single copy
  lastseen[input[i]]=i; // update last seen
  pq.insert(i); // put last seen index into BST
  if (pq.size()==k) { // if all integers seen (nothing missing)
    // get (maximum of endindex requirements) - current index
    interval[i] = (*pq.rbegin())-i+1;
  }
}
// find best answer
unsigned int minlength=-1;
int startindex;
for (int i=0;i<n;i++) {
  if (minlength>interval[i]) { // better answer?
    minlength=interval[i];
    startindex=i;
  }
}
// Your answer is [startindex,startindex+minlength)