【问题标题】:how to track max/min of fifo query如何跟踪fifo查询的最大值/最小值
【发布时间】:2012-07-19 00:17:06
【问题描述】:

我有 fifo 查询我放置和弹出双打的位置。 每次更新后,我需要最大值和最小值。我不需要查询中这些值的位置(或索引)。 如何有效地做到这一点? log(N) 甚至可能是 O(1)?

更新:找到这个Implement a queue in which push_rear(), pop_front() and get_min() are all constant time operations

【问题讨论】:

  • 如果您想在每次更新时跟踪堆栈中的最大值和最小值,那么每次更新都会进行两次计算,因此需要 O(n) 时间。
  • @ReyGonzales O(N) 计算量太大。一定有更好的东西。
  • 如果你检查 n 个元素,那么无论如何你都会有 O(n) 时间。
  • @ReyGonzales 我不需要总是检查 n 个元素。在大多数情况下,最大值和最小值根本不会改变,我根本不需要检查任何东西,因为删除的元素既不是最大值也不是最小值
  • 虽然您的最大值或最小值在更新时可能不会改变,但您仍需要将最新值与最大值和/或最小值进行比较。

标签: algorithm


【解决方案1】:

这是一个棘手的问题。考虑以下几点:

假设在任何给定时间你的 fifo 的大小都是 N。 假设您只用一对浮点数跟踪最小值和最大值。 假设 fifo 的大小保持合理不变。

因此,我们可以假设队列上的一项“操作”在逻辑上由一次推送和一次弹出组成。

假设您正在比较两种处理方法:一种使用堆对,另一种使用简单的比较和搜索。

对于堆方法:

每次操作,你推送到列表和两个堆,然后从列表和两个堆中弹出。堆操作总是O(log(n)),列表操作是O(1),所以N很大,一个操作的时间复杂度是O(log(N))的平均情况。重要的是要注意,无论当前弹出的元素是最小元素还是最大元素,堆操作总是如此复杂。因此,N 次操作的时间复杂度为 O(N*log(N))。

对于天真的方法:

每次操作,你推送和弹出列表,并将弹出的项目与存储的最小值和最大值进行比较。如果该项目与其中任何一项相同,则在列表中搜索具有相同价值的项目(在这种情况下,您会提前中断)或以其他方式搜索整个列表的其余部分,直到找到下一个最佳元素。然后,您使用下一个最佳值更新最小值/最大值。此方法具有 O(1) 典型情况和 O(N) 最坏情况(最小值或最大值需要更新)。重要的是要注意,对于某个范围的 N 数字,您需要更新 min 和 max 的次数变为一个常数,而您不需要更新的次数为 N。因此,N 个操作的时间复杂度为在)。幼稚的案例实际上比更高级的解决方案要好。

也就是说,我认为堆不能有效地删除元素,所以那样你会遇到很多麻烦。

因此,考虑以下伪代码:

queue fifo;
float min, max;

void push(float f)
{
    if (fifo.size == 0)
    {
        min = f;
        max = f;
    }
    else if (f > max) max = f;
    else if (f < min) min = f;

    fifo.push(f);
}

float pop()
{
    if (fifo.size == 0) return (*((float *)NULL)); // explode
    float f = fifo.pop();
    if (fifo.size == 0)
    {
        min = NaN;
        max = NaN;
        return f;
    }
    if (f == max) search_max(fifo);
    if (f == min) search_min(fifo);
    return f;
}

search_max(queue q)
{
    float f = min;
    for (element in q)
    {
        if (element == max) return;
        if (element > f) f = element;
    }
    max = f;
}

search_min(queue q)
{
    float f = max;
    for (element in q)
    {
        if (element == min) return;
        if (element < f) f = element;
    }
    min = f;
}

【讨论】:

  • 想象我的人数一直在增长。所以我总是弹出最小的一个。所以我每次都必须研究,所以在最坏的情况下我有 O(N*N) 。我相信应该有更好的算法。但是我同意你的观点,在这两者之间我会选择一个幼稚的。
  • 如果你确定你的数据集是有序的,你可以做一些事情之一:1)优化排序 2)随机插入顺序。您可以通过添加第一个元素(最小的)然后最后一个(最大的)来欺骗它,然后之间的所有元素都不会触发查找。
【解决方案2】:

如何使用堆 (http://en.wikipedia.org/wiki/Heap_%28data_structure%29)。你可以有两个堆。一个用于提取最小值,一个用于最大值(因为单个堆不能同时提取最小值和最大值)。它也不需要任何空间开销,Big O 是 log n。

【讨论】:

  • 我觉得这太复杂了。
  • 我不确定它是如何工作的,但 java 有一个类优先级队列。你看到了吗。它到底有多复杂??
  • 顺便说一下,我从你的名字中得到了线索,并考虑到你正在使用 Java ;)
猜你喜欢
  • 1970-01-01
  • 2022-01-20
  • 2015-12-30
  • 2021-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-10
  • 1970-01-01
相关资源
最近更新 更多