我被要求实施一个在面试中弹出最常添加项目的堆栈。我给了他以下答案,但他对解决方案不满意。
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
}
}
任何人都可以用正确的方法帮助我吗?
答案 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函数。