【问题标题】:Find the mode (most common element) of an array in C++在 C++ 中查找数组的模式(最常见的元素)
【发布时间】:2014-03-24 03:28:15
【问题描述】:

我在一个面试问题上遇到了这个问题。我想看看 StackOverflow 是如何做到的。

Bjarne Stroustrop 会如何看待我的方式?这有点罗嗦,但不幸的是,我不知道如何使它变得更好。我知道你们会嘲笑我的愚蠢。

template <class T>
T mode(T* arr, size_t n)
// If there's a tie, return an arbitrary element tied for 1st
// If the array size is 0, throw an error
{
   if (n == 0)
   {
       throw("Mode of array of size 0 is undefined, bro.");
   }
   else if (n == 1)
   {
       return arr[0];
   }
   else 
   {
      std::pair<T, int> highest(arr[0], 1);
      std::map<T, int> S;
      S.insert(highest);
      for (T* thisPtr(arr + 1), lastPtr(arr+n); thisPtr != lastPtr; ++thisPtr)
      {
          if (S.count(*thisPtr) == 0)
          {
             S.insert(std::pair<T, int> (*thisPtr, 1);
          }
          else 
          {
             ++S[*thisPtr];
             if (S[*thisPtr] > highest.second)
             {
                 highest = std::pair<T, int> (*thisPtr, S[*thisPtr]);
             }
          }
      }
   }
}

【问题讨论】:

标签: c++


【解决方案1】:

只要 T 实现 std::hash,你就可以这样做:

std::unordered_multiset<T> elems;
std::for_each(arr, arr + size, [&elems](T const & elem) { elems.insert(elem); }

//Now you have elems.count() for each entry
auto max_count = /*Guaranteed minimum value*/
T mode{};
for (auto const & set_elem : elems) {
    if (max(elems.count(set_elem), max_count) == max_count)) {
      mode = set_elem;
    }
}

【讨论】:

    【解决方案2】:

    我想我会使用std::map 进行计数,然后找到计数最多的项目:

    template <class T>
    T mode(T* arr, size_t n) {
        std::map<T, size_t> counts;
    
        for (size_t i=0; i<n; i++)
            ++counts[arr[i]];
    
        return max_element(counts.begin(), counts.end(), 
            [](std::pair<T, size_t> const &a, std::pair<T, size_t> const &b) {
                return a.second < b.second;
            })->first;
    }
    

    如果您期望有大量独特的项目,您可能希望使用 std::unordered_map 而不是 std::map [应该将预期复杂度从 O(n log n) 降低到 O(N)]。

    【讨论】:

      【解决方案3】:

      我发现您的代码存在以下问题。

      冗余校验n == 1

      你可以删除块

      else if (n == 1)
      {
          return arr[0];
      }
      

      不影响结果。

      for循环中的变量声明:

      T* thisPtr(arr + 1), lastPtr(arr+n);`
      

      等价于

      T* thisPtr(arr + 10); T lastPtr(arr+n);
      

      这不是你的意图。编译器也会报错。因此,将他们的声明移到for 循环之外。改变

      for (T* thisPtr(arr + 1), lastPtr(arr+n); thisPtr != lastPtr; ++thisPtr)
      

      T* thisPtr(arr + 1);
      T* lastPtr(arr+n);
      for ( ; thisPtr != lastPtr; ++thisPtr)
      

      简化for循环的内容

      线条

      if (S.count(*thisPtr) == 0)
      {
         S.insert(std::pair<T, int> (*thisPtr, 1));
      }
      

      可以替换为

       ++S[*thisPtr];
      

      这正是您在以下 else 块中所做的事情。

      您可以将整个for循环的内容更改为:

      ++S[*thisPtr];
      if (S[*thisPtr] > highest.second)
      {
         highest = std::pair<T, int> (*thisPtr, S[*thisPtr]);
      }
      

      您需要返回模式

      添加

        return highest.first;
      

      else 块关闭之前。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-13
        • 2018-09-11
        • 1970-01-01
        • 2022-01-24
        • 1970-01-01
        • 2010-12-03
        相关资源
        最近更新 更多