计算区间内值的更有效方法?

时间:2014-10-21 21:00:20

标签: c++ arrays algorithm sorting search

我想确定每个给定间隔(很多)中有多少个输入数组(最多50000个)。

目前,我尝试使用此算法,但速度太慢了:

示例 - 数组:{ - 3,10,5,4,-999999,999999,6000}
示例间隔:[0,11](含)

  1. 排序数组 - O(n * log(n))。 (-999999,-3,4,5,10,6000,999999)
  2. 查找min_index:array[min_index] >= 0 - O(n)。 (对于我的例子,min_index == 2)。
  3. 查找max_index:array[max_index] <= 11 - O(n)。 (对于我的例子,max_index == 4)。
  4. 如果两个索引都存在,那么Result == right_index - left_index + 1(对于我的例子,Result =(4 - 2 + 1)= 3)。

4 个答案:

答案 0 :(得分:2)

你有好主意,但需要修改。您应该使用binary searchO(lg n)时间内找到间隔的开始和结束时间。如果n是数组的长度而q是问题数[a, b],那么你有O(n + q * n)时间,二进制搜索它是O((n + q) lg n)(来自排序数组的n lg n)。 此解决方案的优点是简单,因为C ++具有std::lower_boundstd::upper_bound。你可以使用std::distance。这只是几行代码。

如果q等于n,则此算法具有O(n lg n)复杂度。有待改善?一点也不。为什么?因为问题相当于排序。众所周知,不可能获得更好的计算复杂度。 (通过比较排序。)

答案 1 :(得分:1)

有一个简单的O(n 输入 * m interval )算法:

为了便于实施,我们使用半开间隔。根据需要转换你的。

  1. 将您的间隔转换为半开间隔(始终更喜欢半开间隔)
  2. 保存数组中的所有限制。
  3. 对于输入中的所有元素
    • 对于limits-array中的所有元素
      • 如果输入小于限制
      • ,则增加计数
  4. 浏览您的间隔,并通过减去相应限制的计数来获得答案。
  5. 要获得轻微的性能提升,请在步骤2中对limits-array进行排序。

答案 2 :(得分:1)

将数字的std :: map创建为已排序数组中的索引。

从示例地图[-999999] = 0,地图[-3] = 1,...地图[999999] = 7。

要查找间隔,请找到高于或等于min的最小数字(使用map.lower_bound()),并找到高于最大值的第一个数字(使用map.upper_bound())。

您现在可以从上部索引中减去较低的索引,以在O(log n)中查找该范围内的元素数。

答案 3 :(得分:1)

typedef std::pair<int,int> interval;
typedef std::map<interval,size_t> answers;
typedef std::vector<interval> questions;

// O((m+n)lg m)
answers solve( std::vector<int>& data, questions const& qs ){
  // m = qs.size()
  // n = data.size()

  answers retval;
  std::vector<std::pair<int, size_t>> edges;
  edges.reserve( q.size()+1 );
  // O(m) -- all start and ends of intervals is in edges
  for ( auto q:qs ) {
    edges.emplace_back( q.first, 0 );
    edges.emplace_back( q.second, 0 );
  }
  // O(mlgm) -- sort
  std::sort(begin(edges),end(edges));
  edges.emplace_back( std::numeric_limits<int>::max(), 0 );
  // O(m) -- remove duplicates
  edges.erase(std::unique(begin(edges),end(edges)),end(edges));
  // O(n lg m) -- count the number of elements < a given edge:
  for(int x:data ){
    auto it = std::lower_bound( begin(edges), end(edges), std::make_pair(x,0) );
    it->second++;
  }
  // O(m)
  size_t accum = 0;
  for(auto& e:edges) {
    accum += edges.second;
    edges.second = accum;
  }
  // now edge (x,y) states that there are y elements < x.

  // O(n lg m) -- find the edge corresponding
  for(auto q:questions){
    auto low = std::lower_bound(begin(edges), end(edges),
      std::make_pair(q.first, size_t(0))
    );
    auto high = std::upper_bound(begin(edges), end(edges),
      std::make_pair(q.second, size_t(0))
    }
    size_t total = high->second - low->second;
    answers.emplace(q,total);
  }
  return answers;
}

O((n+m)lg m),其中n是整数计数,m是区间数,x是每个区间重叠的平均区间数。