【问题标题】:Moving window RMQ performance improvement移动窗口 RMQ 性能提升
【发布时间】:2017-02-10 09:38:12
【问题描述】:

假设我有一个长度为N 的整数数组A,我也有一个整数L N。

我试图找到的是范围 [0, L-1], [1,L], [2,L+1]....[N-L,N-1] 的最小值

(就像一个长度为L的从左到右移动的窗口)


我的算法现在是 O(N lg N) 和 O(N lg N) 预处理:

  1. 将所有号码A[0...L-1]保存在多组S中,同时将号码按顺序存储在队列Q中。 [0, L-1] 的最小值只是S 的第一个元素。 O(N lg N)
  2. 弹出Q的第一个元素,在S中找到这个元素并删除。然后将A[L] 推入S。 [1, L] 的最小值只是S 的第一个元素。 O(lg N)
  3. 对所有可能的范围重复第 2 步,每次迭代移动到下一个元素。 O(N)

总计为 O(N lg N)。


我想知道是否有任何算法可以达到比这更好的要求:

  1. 预处理时间(如果需要)为 O(N)
  2. O(1) 的查询时间

我对 RMQ 做了一些研究,我发现最近的方法是使用稀疏表,它实现 O(1) 查询时间但 O(N lg N) 预处理时间。 reduce RMQ to LCA问题的另一种方法可以满足要求,但需要对数组A进行一些限制。

那么有没有可能,不限制A,在解决我的问题时可以满足要求?

【问题讨论】:

    标签: c++ algorithm rmq


    【解决方案1】:

    是的,使用deque。我们将保持元素按升序排序,因此第一个元素始终是[i - L + 1, i] 中的最小值,对于当前位置i。我们不会保留实际元素,而是保留它们的位置。

    d = empty deque
    for i = 0 to n-1:
    
        // get rid of too old elements
        while !d.empty && i - d.front + 1 > L:
            d.pop_front()
    
        // keep the deque sorted
        while !d.empty && A[d.back] > A[i]        
            d.pop_back()
    
        d.push_back(i)
        // A[d.front] is the minimum in `[i - L + 1, i]
    

    由于每个元素最多进入和离开双端队列一次,因此这是O(n)

    【讨论】:

    • 这太棒了,没想到这个……谢谢!!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多