实现弹出最常添加的项目的堆栈

Implement the stack that pops the most frequently added item

本文关键字:添加 项目 堆栈 常添加 实现      更新时间:2023-10-16

我被要求实现一个堆栈,该堆栈弹出面试中最常添加的项目。我给了他以下答案,但他对解决方案不满意。

class stack 
{
  // Map of value and count 
  map<int,int> Cntmap; 
  public: 
  void push(int val) 
  { 
    // Find val in map 
    // if found then increment map count 
    // else insert a pair (val,1) 
  } 
  int pop( ) 
  { 
    // Find the Key in Cntmap with max value 
    // using std::max_element 
    // Decrement the Cntmap count for the popped val 
  } 
}

谁能帮助我正确的方法?

这是一个

有趣的问题,因为在push中,你抬头使用键,并在pop中使用映射值。 std::map立即支持第一个:您所要做的就是:

++ CntMap[ val ];

如果键不是,[]运算符将插入一个条目present,使用其默认值初始化映射类型构造函数,对于int会导致0。 你甚至没有需要if.

二是比较难。 然而,评论给出了解决方案:您只需要一个自定义Compare,这需要两个 std::pair<int, int> ,并比较第二个元素。 std::max_element会将迭代器返回到您所在的条目感兴趣,所以你可以直接使用它。 到目前为止一切顺利(和非常简单(,但您必须考虑错误条件:什么如果Cntmap为空,则发生。 您可能希望删除元素,如果计数下降到0(同样,很简单,因为你有一个迭代器指定条目,包括键和值(。

最后,如果这是一个面试问题,我肯定会指出pop操作是O(n)的,并且它可能值得(尽管要复杂得多(到维护二级索引,以便我可以找到最大值元素更快。 (如果我在面试,那将是我的下一个问题。 然而,显然对于高级程序员来说。

仅使用单个(简单(数据结构的问题在于,其中一个操作必须是线性的(它必须搜索所有元素(,这还不够好。在您的情况下,我相信线性时间操作是pop.

我的尝试:

  • 有一个链表(将按频率排序(。

  • 将值映射到链表中的节点。

  • 若要推送,请在映射中查找值以获取链接列表节点。

    • 如果找到,请增加频率并适当地移动节点以保持链表排序。

    • 如果未找到,请将频率设置为 1,然后插入到链接表中的适当位置。

  • 要弹出,请降低链表第一个节点的频率并适当地移动它以保持链表的排序,并返回适用的值。

如果有许多节点具有相同的频率,您可能会遇到一些非常糟糕的最坏情况行为。应该可以通过拥有某种链表的链接列表来获得恒定的时间添加/递增/减少,大型链表中的每个节点代表一个特定的频率,每个链表代表具有该频率的所有节点。

通过上述优化,pop 可以是 O(1(,推送可以是 O(log n(。如果使用unordered_map (C++11(,则推送可以是 O(1(。

另一个(可能稍微简单一些(的选择是做一些类似于上面的事情,但使用heap而不是链接列表。

我认为在您

的情况下,Max-Heap 会更好,而不是 Map。您可以以类似的方式维护计数器。请注意,堆的键将是计数,而不是实际值本身。当您必须插入一个值时,请搜索该值,如果找到,则将其键递增,否则,将带有键的值插入为 1。希望这有帮助。

解决方案可能是包装Boost.Bimap(组织使用boost吗?(。 有了这个,您可以创建一个容器,该容器在一个方向上提供有序访问,并在另一个方向上进行哈希处理。您的推送和弹出实现将使用 bimap 的替换函数。