算法研究(四) 一维模式识别

来源:互联网 发布:.net程序员项目经验 编辑:程序博客网 时间:2024/05/11 16:05
题目:这是一个一维模式识别问题,问题的输入是一个具有n个浮点数据字的向量x,其输出是在输入的任何相邻子向量中找出的最大和,例如,如果输入向量包含下面10个元素:

图中显示了找出的子向量。
按照时间复杂度由大到小,以下给出解此题的四种算法:

 算法一:三重循环比较 O(n3)
伪码如下:
[cpp] view plaincopy
  1. max = 0;  
  2. for (i = 0; i < n; ++i)  {  
  3.     for (j = 1; j < n; ++j) {  
  4.             sum = accumulate(data, i, j);  
  5.             if max < sum  
  6.                 max = sum;  
  7.           }  
  8. }  

此算法最为直观,但也最为耗时,累加accumulate的复杂度为n,加上外面的两重循环,其复杂度为O(n3)。

 算法二:两重循环(使用累加) O(n2)

伪码如下: 

[cpp] view plaincopy
  1. max = 0;  
  2. for (i = 0; i < n; ++i) {  
  3.     sum = 0;  
  4.     for (j = 1; j < n; ++j) {  
  5.             sum += data[j - 1];  
  6.             if max < sum  
  7.                 max = sum;  
  8.           }  
  9. }  
通过对前一个子向量求出的和的利用,我们轻易的将时间复杂度降低到了O(n2)。


 算法三:分治法 O(nlogn)
我们把向量分成两段,那么该向量的最大子向量要么出现在a段或是b段,要么出现在a,b的中间,如图所示,对a,b进行递归,得出ma, mb, 计算出mc,返回他们中的最大值。


伪码如下: 
[cpp] view plaincopy
  1. double func(double[] data, int i, int j) {  
  2.     if (i >= j)  
  3.         return 0;  
  4.   
  5.     middle = (i + j) / 2;  
  6.     ma = func(data, i, middle);  
  7.     mb = func(data, middle, j);  
  8.       
  9.     lmax = 0;  
  10.     sum = 0;  
  11.     for (k = m - 1; k >= i; --k) {  
  12.         sum += data[k];  
  13.         lmax = max(lmax, sum);  
  14.           }  
  15.     rmax = 0;  
  16.     sum = 0;  
  17.     for (k = m; k < j; ++k) {  
  18.         sum += data[k];  
  19.         rmax = max(rmax, sum);  
  20.           }  
  21.     mc = lmax + rmax;  
  22.       
  23.     return max(ma, mb, mc);  
  24. }   

容易看出此算法的复杂度为O(nlogn)。

 算法四:线性扫描 O(n)
如果我们仔细分析该问题的特点,实际上会发现存在一个复杂度只有O(n)的扫描算法。
[cpp] view plaincopy
  1. maxvalue = 0;  
  2. maxendvalue = 0;  
  3. for (i = 0; i < n; ++i) {  
  4.     maxendvalue = max(maxendvalue + data[i], 0);  
  5.     maxvalue = max(maxvalue, maxendvalue);  
  6. }  
是不是很神奇,呵呵~~
原创粉丝点击