【问题标题】:Max value's index in array with uniform distribution when there are several max values, and number of max values is known当有多个最大值时,最大值在数组中的索引,均匀分布,并且最大值的个数已知
【发布时间】:2019-05-09 04:52:37
【问题描述】:

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

例如:如果我们有向量 (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() 以找到均匀分布的最大索引,并使用一些计数器变量来了解何时在循环中获得正确的最大索引。但这并没有提高运行时间,因为randO(1) 中运行。

有更好的主意吗?

【问题讨论】:

  • 嗯,第一个算法已经是O(n),你不能再低了,因为你需要读取每个元素,所以我想说你不能提高算法的运行时复杂度(我认为这里的“运行时间”是什么意思)。
  • #include &lt;bits/stdc++.h&gt; -- 这是一个面试问题 -- 好吧,如果这是一个 C++ 编程职位,任何称职的公司都会拒绝这个。

标签: c++ algorithm performance


【解决方案1】:

仅仅因为某些东西具有相同的大 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);
}

【讨论】:

  • OP 的第一个问题的算法(没有计数)已经一次性完成了。如果您从第二个问题开始,我认为您不会改善第二个问题的运行时间。
  • @Nelfeal 我不确定 OP 的算法是否在索引之间统一挑选。
  • 它是(就rand 而言)。对于单个元素,选择它的概率为1。添加第二个元素时,选择该新元素的概率为1/2,因此仍然是一致的。当添加第三个时,选择这个的概率是1/3,所以留在前两个之一的概率是2/3,因此每个都有一个被选中的整体概率1/2 * 2/3 = 1/3。所以还是统一的。以此类推。
  • @Nelfeal 啊,好的。好吧,让我们假设 rand() 是和“昂贵的 O(1)”调用。计数让你调用一次
猜你喜欢
  • 2013-01-11
  • 2021-12-03
  • 1970-01-01
  • 2020-04-02
  • 1970-01-01
  • 2012-04-13
  • 2016-08-24
  • 1970-01-01
  • 2016-06-27
相关资源
最近更新 更多