4.1求最大子数组问题
根据这17天的股票价格分析何时买进,何时买进、何时卖出可达收益最大化?
1.暴力求解
通过 对 ( n 2 ) \binom{n}{2} (2n)个日期组合处理来求解,时间复杂度为O(n)
2.变换问题
从Price的角度(值)变为Change(值的变化量),问题转化为寻找“Change数组”的和最大非空连续子数组。
3.分治方法(分解、解决、合并)
分治算法中,我们递归的求解一个问题,有三个步骤
a.分解:将原问题变为规模更小的子问题
b .解决:子问题规模足够小时停止递归,直接求解
c .合并;将子问题的解合并成原问题的解
本题中:通过Change[low,high]的中点mid=low+high)/2来划分子问题
分解:求Change[low,high]的最大子数组 → \rightarrow →
子问题1.求Change[low,mid]的最大子数组;
子问题2.求 Change[mid+1,high]的最大子数组;
子问题3.求跨越mid的最大子数组
解决:当low=high时,停止递归,直接求解 → \rightarrow →
最大子数组即为Change[low] (只有一个元素)
合并:取三个子问题解中的最大者
4.代码(leetcode剑指offer.42)
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int left=0;
int right=nums.size()-1;
int mid=(left+right)/2;
return findMaxSubArry(nums,left,right);
}
int findMaxSubArry(vector<int>&nums,int l,int r){
//停止递归求解
if(l==r)return nums[l];
else{
//分解为子问题
int m=(l+r)/2;
int lmax=findMaxSubArry(nums,l,m);
int rmax=findMaxSubArry(nums,m+1,r);
int mmax=findMaxCrossArry(nums,l,r,m);
//合并
return max(max(lmax,rmax),mmax);
}
}
//求跨越m的最大子数组
int findMaxCrossArry(vector<int>&nums,int l,int r,int m){
int lmax=INT_MIN;
int lcur=0;
int rmax=INT_MIN;
int rcur=0;
for(int i=m;i>=l;i--){
lcur+=nums[i];
if(lcur>lmax)
lmax=lcur;
}
for(int j=m+1;j<=r;j++){
rcur+=nums[j];
if(rcur>rmax)
rmax=rcur;
}
return lmax+rmax;
}
};
5.分治算法分析
T ( n ) = { O ( 1 ) n = 1 2 T ( n / 2 ) + O ( n ) n > 1 T(n)=\begin{cases} O(1) &n=1 \\ 2T(n/2)+O(n)&n>1\\ \end{cases} T(n)={O(1)2T(n/2)+O(n)n=1n>1
故时间复杂度为O(nlgn)
6.改进方法(动态规划O(n))
略