【问题标题】:Finding key corresponding to max value in c++ map在c ++映射中查找与最大值对应的键
【发布时间】:2021-10-17 13:20:53
【问题描述】:

给定一个数字,说“KEY”并映射 myMap。我试图在地图 myMap 中找到一个最小的键 k(条件:k

例子:

map <int, int> myMap = {{3,1}, {4,3}, {5,2}, {6,3}, {7,2}, {8,5}};
                             // ^^^
int KEY = 7;

答案是 4,因为对于所有小于 7(KEY) 的键,键 4 和键 6 的最大值为 3。4 是最小的键。

地图动态增加,有几个这样的带有KEY的查询。

我试图在 O(logN) 时间内得到 {k,v} 对

我在使用 lower_bound 后卡住了。使用下限给了我最大的“k”,使得 k

更新:

我也确保在对数时间内更新地图。整数不超过 10^5。是否可以使用其他一些数据结构和方法(在这种情况下,它看起来像动态编程/二进制搜索)在对数时间内解决这个问题?

【问题讨论】:

  • 你可以在每个节点中存储一个key,对应所有前面节点中的最大值。或者有一个单独的键映射到“较小键中最大值的键”。这将使回答这个问题的速度更快 - 但当然它会使更新地图的速度变慢。这可能是也可能不是一个合适的权衡。
  • 如果您想通过某些条件进行有效搜索,它必须是键的一部分,而不是值的一部分。似乎std::map&lt;std::pair&lt;int,int&gt;,T&gt;(或一组)与自定义operator&lt; 会更好匹配。
  • 这种结构是不可能的。您的条件使您需要考虑 O(N) 个元素。 N 个未知排序的元素。
  • {4,3}{6,3} 之间你会如何选择?它们都有
  • @IgorTandetnik 没错。这会使更新地图变慢。所以我们不能使用它。我会相应地更新我的问题。

标签: c++ algorithm dictionary data-structures stl


【解决方案1】:

这个怎么样。你维护一个次要地图,你的主要地图的一个子集。具体来说,当且仅当主映射中所有较小的键对应较小的值时,此辅助映射才会包含 {k, v}

对于您的{3,1}, {4,3}, {5,2}, {6,3}, {7,2}, {8,5} 示例,此辅助映射将是{3,1}, {4,3}, {8,5}。观察值如何随着键单调增加。

如何使用此地图来回答问题应该很明显 - 只需使用 lower_bound 查找密钥即可。在示例中,对于 7 的键,查找将找到 4,即正确答案。

现在,如何维护这张地图。将{k, v} 插入主映射时,使用lower_bound 在辅助映射中查找k。有两种可能:

  • 存在具有相同或更大值的较小键。什么都不做,次要地图不需要更新。

  • 不存在较小的键,或者较小的键对应较小的值。那么

    • {k, v} 插入辅助地图
    • 依次走key,从k开始,直到遇到值更大的keyk',或者到达终点。擦除kk' 之间的范围(不包括两者),或从k(不包括)到末尾。

表面上,这最后一步看起来是线性的 - 但实际上它是摊销常数。在 N 插入之后,此步骤最多必须遍历 2*N 元素(例如,第一个 N-1 步骤每个插入一个元素,最后一步将它们全部删除并插入一个)。

【讨论】:

  • 看起来这行得通。感谢您指出摊销常数部分。
【解决方案2】:

是否有任何数据结构可以帮助我在 logN 时间内实现这一目标?

除非您能够以有意义的方式组合这些值,否则不会。所有(几乎)log N 算法都依赖于分而治之的方法。

您基本上有两个不相关的序列。树映射的键允许你做 log N 的事情,但是你需要在一个非结构化序列上进行另一个搜索,这是 O(N)。

因此,要在 O(log N) 上完成此操作,您需要以某种方式将键和值组合起来,或者按照@Igor 建议的路线注释进行操作,这本质上是一张地图。

当然,调整实现可能会带来好处,但不会带来 O(N) -> O(log N) 类型的好处。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-08
    • 1970-01-01
    • 1970-01-01
    • 2017-02-04
    相关资源
    最近更新 更多