码迷,mamicode.com
首页 > 编程语言 > 详细

【算法基础】由股票收益问题再看分治算法和递归式

时间:2015-05-26 16:10:58      阅读:279      评论:0      收藏:0      [点我收藏+]

标签:递归   插入   基础   分析   

最大子数组问题

最近有一个比较火的话题,股票,那么这一篇就由此引入来进一步学习分治算法。在上一篇博客中已经对插入排序和分治算法做了初步的介绍,建议在看一篇前先看看:【算法基础】由插入排序看如何分析和设计算法

当然了,这篇博客主要用来介绍算法而非讲解股票,所以这里已经有了股票的价格,如下所示。

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
股票价格 50 57 65 75 67 60 54 51 48 44 47 43 56 64 71 65 61 73 70
价格波动 0 7 8 18 -8 -7 -6 -3 -3 -4 3 -4 13 10 7 -6 -4 12 -3

价格表已经有了问题是从哪一天买进、哪一天卖出会使得收益最高呢?你可以认为在价格最低的时候买入,在价格最高的时候卖出,这是对的,但不一定任何时候都适用。在这里的价格表中,股票价格最高的时候是第3天、价格最低的时候是第11天,怎么办?让时间反向行驶?

就像我以前参加学校里的程序设计竞赛时一样,也可以用多个for循环不断的进行比较。这里就是将每对可能的买进和卖出日期进行组合,只要卖出日期在买进日期之前就好,这样在18天中就有C218种日期组合,也可以写成(182)。因此对于n天,就有(n2)种组合,而(n2)=Θ(n2),另外处理每对日期所花费的时间至少也是常量,因此这种方法的运行时间为Ω(n2)

然后,我们在学习算法,自然要以算法的角度来看这个问题。比起股票价格,我们更应该关注价格波动。如果将这个波动定义为数组A,那么问题就转换为寻找A的和最大的非空连续子数组。这种连续子数组就是标题中的最大子数组(maximum subarray)。将原表简化如下:

数组 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
A 7 8 18 -8 -7 -6 -3 -3 -4 3 -4 13 10 7 -6 -4 12 -3

在这个算法中,常常被说成是“一个最大子数组”而不是“最大子数组”,因为可能有多个子数组达到最大和。

只有当数组中包含负数时,最大子数组问题才有意义。如果所有数组元素都是非负的,最大子数组问题没有任何难度,因为整个数组的和肯定是最大的。

使用分治思想解决问题

我们将实际问题转换为算法问题,在这里也就是要寻找子数组A[low...high]的最大子数组。分治思想意味着将问题一分为二,这里就需要找到数组的中间位置mid,然后考虑求解2个子数组A[low…mid]和A[mid+1…high]。而A[low...high]的任何连续子数组A[i...j]所处的位置必然是以下情况之一:
1)完全位于子数组A[low…mid]中,因此lowijmid
2)完全位于子数组A[mid+1…high]中,因此mid<ijhigh
3)跨越中点mid,因此lowimidjhigh

伪代码如下:

FIND-MAX-CROSSING-SUBARRAY(A,low,mid,high)
1   left-sum = -10000
2   sum = 0
3   for i = mid downto low
4        sum = sum + A[i]
5        if sum > left-sum
6             left-sum = sum
7             max-left = i
8   right-sum = -10000
9   sum = 0
10  for j = mid + 1 to high
11       sum = sum + A[i]
12       if sum > right-sum
13            right-sum = sum
14            max-right = j
15   return (max-left, max-right, left-sum + right-sum)
#include <iostream>
#include <cstdio>

using namespace std;

int const n=18;
int A[n]={7,8,18,-8,-7,-6,-3,-3,-4,3,-4,13,10,7,-6,-4,12,-3};
int B[3];
int low,high,mid;
int max_left,max_right;
int sum;

void find_max_crossing_subarray(int A[],int low,int mid,int high);

int main()
{
    find_max_crossing_subarray(A,0,7,15);
    for(int i=0;i<3;i++)
    {
        printf("%d ",B[i]);
    }
    return 0;
}

void find_max_crossing_subarray(int A[],int low,int mid,int high)
{
   int left_sum=-10000;
   sum=0;
   for(int i=mid;i>=low;i--)
   {
       sum=sum+A[i];
       if(sum>left_sum)
       {
           left_sum=sum;
           max_left=i;
       }
   }
   int right_sum=-10000;
   sum=0;
   for(int j=mid+1;j<=high;j++)
   {
       sum=sum+A[j];
       if(sum>right_sum)
       {
           right_sum=sum;
           max_right=j;
       }
   }
   B[0]=max_left;
   B[1]=max_right;
   B[2]=left_sum+right_sum;
}

程序大概就是这个样子……也可以将数组A放到main函数中输入。

【算法基础】由股票收益问题再看分治算法和递归式

标签:递归   插入   基础   分析   

原文地址:http://blog.csdn.net/nomasp/article/details/46007967

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!