最大子数组问题

        今天跟大家讨论的是最大子数组问题。

问题描述:

        一个想靠着股票发家致富的股票迷提出了这么一个问题,在已经知道一个股票17天的股票价格后,股票迷就希望可以知道什么时候买入这个股票,之后在什么时候将该股票卖出才可以得到最大的利润。

问题分析:

        在知道我们股票迷的需求之后,最暴力的解决方法不外乎是简单滴尝试每对可能的买进和卖出日期组合,这样自然就可以找到最适合的匹配;不过问题既然来了,我们还是本着用尽可能好的方法来解决该问题。首先,我们需要将问题变换一下,已经知道的是每天的股票价格,我们做一个减法运算,把股票价格数据变换成股票价格的日变化值,然后现在将这些数据看成是一个数组,那我们的任务就成了找到一个(注意,可能有多个最大子数组)这个数组里边的和最大子数组(也就是在数组中找到一个区间使得这个区间的股票价格增长值最大)。

        我们考虑使用分之策略来求解最大子数组问题。用分治技术意味着我们先要将子数组划分成为两个规模尽量相等的子数组,也就是找到数组A[low..high]中间位置mid,那么我们要找数组A的任意一个子数组,其所处的位置必然是以下三种情况:

  • 完全位于A[low..mid]
  • 完全位于A[mid..high]
  • 跨越了中点mid
       我们求解最大子数组问题也就成了在这三块区域找到各自最大的的子数组然后进行比较,最大的即是我们的目标数组,不多说了,直接撸代码,时间复杂度O(nlgn),代码不是很复杂,有不明白的可以给我留言。
#include<iostream>  
#include<math.h>  
#include<limits.h>  
using namespace std; 
struct sub{		//声明一个结构体变量用来存储子数组的信息 
	int low;	
	int high;
	int sum;	//数组和 
};
sub find_Maxsubrray(int *A,int low,int high);    //寻找最大子数组   
sub find_Maxcrosub(int *A,int low,int mid,int high);   //找到跨越中点的最大子数组   

int main()  
{  
    int A[7]={3,-1,-4,6,5,-2,7};  
    sub sub_result;
    sub_result=find_Maxsubrray(A,0,6);  
    cout<<"和最大的数组是从"<<sub_result.low<<"到"<<sub_result.high<<",和是"<<sub_result.sum;  
    cout<<endl;  
    return 0;  
} 
sub find_Maxsubrray(int *A,int low,int high){
	int mid;
	sub left_sub,right_sub,cross_sub;
	if(high==low)
	{
		cross_sub.low=low;
		cross_sub.high=high;
		cross_sub.sum=A[low];
		return cross_sub;	
	}
	else{
		mid=(int)floor((low+high)/2.0);
		left_sub=find_Maxsubrray(A,low,mid);
		right_sub=find_Maxsubrray(A,mid+1,high);
		cross_sub=find_Maxcrosub(A,low,mid,high);
		if(left_sub.sum>=right_sub.sum&&left_sub.sum>=cross_sub.sum)
			return left_sub;
		else if(right_sub.sum>=left_sub.sum&&right_sub.sum>=cross_sub.sum)
			return right_sub;
		else
			return cross_sub;
	}
		
}  
sub find_Maxcrosub(int *A,int low,int mid,int high){
	int left_sum,sum,right_sum,max_left,max_right;
	sub sub_max;
	left_sum=INT_MIN;
	sum=0;
	for(int i=mid;i>=low;i--){
		sum+=A[i];
		if(sum>left_sum){
			left_sum=sum;
			max_left=i;
		}
	}
	right_sum=INT_MIN;
	sum=0;
	for(int j=mid+1;j<=high;j++){
		sum+=A[j];
		if(sum>right_sum){
			right_sum=sum;
			max_right=j;
		}
	}
	sub_max.low=max_left;
	sub_max.high=max_right;
	sub_max.sum=left_sum+right_sum;
	return sub_max ;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值