连续,固定长度子序列的最大差异

时间:2014-12-05 10:13:02

标签: c++ algorithm subsequence

将序列的位移定义为最大和最小元素之间的差异。 给定一系列整数,找到长度为m的所有连续子序列的最大位移。

例如,如果我们的序列是[1,5,7,0,2,-4]和m = 3,

  • [1,5,7]有位移6。
  • [5,7,0]有位移7.
  • [7,0,2]有位移7。
  • [0,2,-4]有位移6.
  • 所以最大位移是7。

如果我们让n表示输入序列的长度,那么我的解决方案在O(nlog(m))时间内运行。有什么方法可以做得更好吗?我觉得必须有一个我缺失的线性时间算法。 出于这个问题的目的,我所关心的只是渐近时间的复杂性。

#include <vector>
#include <set>
#include <iostream>
int find_max_displacement(std::vector<int> seq, int m){
    std::multiset<int> subseq;
    // insert the m items of first subsequence into tree
    for (int i = 0; i < m; i++){
        subseq.insert( seq[i] );
    }
    int max_disp = *subseq.rbegin() - *subseq.begin(); // max minus min
    for (int i = 0; i < seq.size() - m; i++){
        subseq.erase(subseq.find(seq[i]));  // kick oldest element out of subsequence
        subseq.insert( seq[i+m] );          // insert new element into subsequence
        int new_disp = *subseq.rbegin() - *subseq.begin();
        if (new_disp > max_disp){
            max_disp = new_disp;
        }
    }
    return max_disp;
}
int main(){
    std::vector<int> arr {1, 5, 7, 0, 2, -4};
    int max_disp = find_max_displacement(arr, 3);
    std::cout << max_disp << std::endl;
    return 0;
}

1 个答案:

答案 0 :(得分:3)

你是对的,有一个线性时间算法。您可以计算具有滑动最大值的数组和具有最小滑动的数组,并找到这两个数组之间的最大差异。

在线性时间内计算滑动最大值是一个标准问题,对不同技术here有一个很好的解释。如果链接断开,这里是该链接的线性时间算法的描述:

  

这里给出的算法是递增的最小值算法;它   需要O(n)时间和O(k)空间。一般的想法是找到   在窗口中最小,然后在剩余的最小值   窗口,等等。升序最小值之间的值可以忽略。

     

更正式地说,让W是长度为k的值的向量。定义   升序mimima序列A,如下:

     

令A [0]为W中的最小值,并且对于j> 0,令A [j]为最小值   W中的值,索引大于A [j-1]的索引。 (如果两个   位置具有相同的最小值取后一个。)示例:

 W = 5,2,8,6,4,7 
 A = 2,4,7 
     

显然A的长度是1,如果是   如果W是单调的,W中的最小值是W和k中的最后一个元素   越来越多。现在假设我们在V上有一个窗口W并且我们知道   上升的最小值向量A.考虑当我们移动时会发生什么   窗口一个位置。我们在窗口的末尾添加一个元素   从窗口的开头删除一个元素。设x为   新添加的元素。然后A可以通过

更新      

a:删除大于或等于x的所有元素

     

b:将x附加到A,

     

c:并删除A的初始元素(如果从窗口中删除)。

     

我们不需要记录窗口;我们所需要的只是   递增的最小序列。但是有必要记录一下   序列中的条目将从窗口中删除。为此原因   如果A的元素有两个字段,第一个是a,这很有用   V的值,即某些i的V [i],第二个是索引   当条目从窗口消失时。这发生了k个条目   后面。

     

由于A的长度是有界的,因为A是队列,所以很自然   将其存储在环形缓冲区中。

     

步骤(b)和(c)是直截了当的,没有重要意义   备择方案。在步骤(a)中,我们需要找到A中的最后一个值   小于新添加的x。乍一看似乎是一个   A的二进制搜索将是最佳的。不是这种情况;最优的   搜索是从一个简单的循环中回到前面。

     

证明很简单;线性搜索循环删除元素   逐个删除每次删除的O(1)时间成本。平均而言   A的删除次数与添加次数相同。该   结果是将窗口移动一个位置的平均时间成本   是O(1)。