当存在多个最大值且已知最大值数目时,数组中具有均匀分布的最大值的索引

时间:2018-12-07 12:08:06

标签: c++ algorithm performance

这是我看到的面试问题,没有很好的解决方法。
问题的第一部分是:
给定一个整数向量,找到最大值的索引。但是,如果有多个最大值-您希望最大值的每个索引都有相同的概率被选择。

例如:如果我们有向量(0,1,2,2,2,2),则索引2的概率为0.25(与索引3、4、5相同)。

您可以像这样在C ++中解决它:

#include <iostream>
#include <bits/stdc++.h> 
using namespace std;

int getIndex(const vector<int>& numbers) {
  int maxNum = numeric_limits<int>::min();
  size_t idx = -1;
  size_t maxNumCtr = 0;

  for(size_t i = 0; i<numbers.size(); ++i) {
    int num = numbers[i];
    if(num > maxNum) {
      idx = i;
      maxNum = num;
      maxNumCtr = 1;
    } else if (num == maxNum) {
      maxNumCtr ++;
      idx = ((rand() % maxNumCtr) == 0) ? i : idx; 
    }
  }
  return idx;
} 

第二部分是:
现在,该函数有一个附加参数,用于指示向量中最大值出现的次数。尝试改善您编写的算法的运行时间。

我的想法是,您可以在函数开始时仅计算一次rand(),以找到均匀分布的max索引,并使用一些计数器变量来知道何时在循环中获得正确的max索引。但这并不能改善运行时间,因为randO(1)中运行。

有更好的主意吗?

1 个答案:

答案 0 :(得分:0)

仅仅是因为某些事物具有相同的big-O复杂性并不意味着它具有相同的运行时间。采访要求改变不变因素,而不是提高复杂性。

这就是我不加计数的方式

// Undefined if first == last
template<typename ForwardIterator, typename URBG>
int getIndex(ForwardIterator first, ForwardIterator last, URBG&& gen)
{
    int max = *std::max_element(first, last);
    std::vector<double> weights;
    std::transform(numbers.begin(), numbers.end(), std::back_inserter(weights), [max](int i){ return i == max; });
    // or auto weights = numbers | ranges::view::transform([max](int i){ return i == max; });

    std::discrete_distribution<int> dis(weights.begin(), weights.end());
    return dis(gen);
}

具有2个传递数据,并构造一个相同大小的std::discrete_distribution

如果您已经可以从中选择数量,则可以一次通过并使用std::uniform_int_distribution

// Undefined if first == last
template<typename ForwardIterator, typename URBG>
int getIndex(ForwardIterator first, ForwardIterator last, size_t max_count, URBG&& gen)
{
    std::uniform_int_distribution<> dis(1, max_count);
    std::size_t nth = dis(gen);

    ForwardIterator best = first;
    std::size_t nth_best = nth;

    for (ForwardIterator it = first; it != last; ++it)
    {
        if (*best < *it)
        {
            // new max
            best = it;
            nth_best = nth;
        }
        else if (*it < *best) {} // nothing
        else if ((--nth_best) == 0) 
        {
            // found nth of this value
            best = it;
        }
    }

    return std::distance(first, best);
}