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

时间:2013-07-11 08:15:02

标签: c++ data-structures

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

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 
  } 
}

任何人都可以用正确的方法帮助我吗?

4 个答案:

答案 0 :(得分:3)

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

++ CntMap[ val ];

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

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

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

答案 1 :(得分:1)

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

我的尝试:

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

  • 为链表中的节点提供值映射。

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

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

    • 如果未找到,请将频率设置为1并插入相应位置的链接列表。

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

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

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

另一个(可能稍微简单)选项是执行类似于上面的操作,但使用heap而不是链接列表。

答案 2 :(得分:0)

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

答案 3 :(得分:0)

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