algorithm - 找到构成序列的最大子集

标签 algorithm time-complexity

我在一个面试论坛上遇到了这个问题。,

给定一个可能包含重复项的 int 数组,找出其中构成序列的最大子集。 例如。 {1,6,10,4,7,9,5} 那么 ans 是 4,5,6,7 排序是一个显而易见的解决方案。这能在 O(n) 时间内完成吗?

我对这个问题的看法是,这不能在 O(n) 时间内完成,原因是如果我们可以在 O(n) 时间内完成,我们也可以在 O(n) 时间内完成排序(不知道上限)。 由于随机数组可以按顺序包含所有元素,但顺序是随机的。

这听起来合理吗?你的想法。

最佳答案

我相信它可以在 O(n) 中解决,如果您假设您有足够的内存来分配一个大小等于最大值的未初始​​化数组,并且该分配可以在常数时间内完成。诀窍是使用惰性数组,它使您能够在线性时间内创建一组项目,并在恒定时间内进行成员测试。

阶段 1:遍历每个项目并将其添加到惰性数组。

阶段 2:遍历每个未删除的项目,并删除所有连续的项目。

在第 2 阶段,您确定范围并记住它是否是迄今为止最大的范围。可以使用双向链表在恒定时间内删除项目。

下面是一些非常笨拙的代码来演示这个想法:

int main(int argc,char **argv)
{
  static const int n = 8;
  int values[n] = {1,6,10,4,7,9,5,5};
  int index[n];
  int lists[n];
  int prev[n];
  int next_existing[n]; // 
  int prev_existing[n];
  int index_size = 0;
  int n_lists = 0;

  // Find largest value
  int max_value = 0;
  for (int i=0; i!=n; ++i) {
    int v=values[i];
    if (v>max_value) max_value=v;
  }

  // Allocate a lazy array
  int *lazy = (int *)malloc((max_value+1)*sizeof(int));

  // Set items in the lazy array and build the lists of indices for
  // items with a particular value.
  for (int i=0; i!=n; ++i) {
    next_existing[i] = i+1;
    prev_existing[i] = i-1;
    int v = values[i];
    int l = lazy[v];
    if (l>=0 && l<index_size && index[l]==v) {
      // already there, add it to the list
      prev[n_lists] = lists[l];
      lists[l] = n_lists++;
    }
    else {
      // not there -- create a new list
      l = index_size;
      lazy[v] = l;
      index[l] = v;
      ++index_size;
      prev[n_lists] = -1;
      lists[l] = n_lists++;
    }
  }
  // Go through each contiguous range of values and delete them, determining
  // what the range is.
  int max_count = 0;
  int max_begin = -1;
  int max_end = -1;
  int i = 0;
  while (i<n) {
    // Start by searching backwards for a value that isn't in the lazy array
    int dir = -1;
    int v_mid = values[i];
    int v = v_mid;
    int begin = -1;
    for (;;) {
      int l = lazy[v];
      if (l<0 || l>=index_size || index[l]!=v) {
        // Value not in the lazy array
        if (dir==1) {
          // Hit the end
          if (v-begin>max_count) {
            max_count = v-begin;
            max_begin = begin;
            max_end = v;
          }
          break;
        }
        // Hit the beginning
        begin = v+1;
        dir = 1;
        v = v_mid+1;
      }
      else {
        // Remove all the items with value v
        int k = lists[l];
        while (k>=0) {
          if (k!=i) {
            next_existing[prev_existing[l]] = next_existing[l];
            prev_existing[next_existing[l]] = prev_existing[l];
          }
          k = prev[k];
        }

        v += dir;
      }
    }
    // Go to the next existing item
    i = next_existing[i];
  }

  // Print the largest range
  for (int i=max_begin; i!=max_end; ++i) {
    if (i!=max_begin) fprintf(stderr,",");
    fprintf(stderr,"%d",i);
  }
  fprintf(stderr,"\n");

  free(lazy);
}

关于algorithm - 找到构成序列的最大子集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7683077/

相关文章:

algorithm - 这些循环 1 和 2 的时间复杂度是多少

algorithm - P2P distribution - 监督节点的抽象算法

java - 如何让两个线程执行两个不同的循环或方法?

python - python 的 if 字符串中的子字符串的运行时

javascript - 这个就地数组反转的时间复杂度是多少?

python - 一个循环的时间复杂度

algorithm - 如何修改id混淆混洗位算法中的掩码?

java - 如何创建平衡的团体

algorithm - 计数最小草图 : How to handle counters overflow?

python - 转换整数数组并计算总和