一、请以伪代码描述最大字段和的分治算法
//最大子段和分治
int MaxSubSum(int *a,int left,int right)
{
int sum = 0;
if(left==right)
{
sum = a[left]>0?a[left]:0;
}
else
{
int middle = (left+right)/2;
int leftsum = MaxSubSum(a,left,middle);
int rightsum = MaxSubSum(a,middle+1,right);
int s1=0;
int lefts=0;
for(int i=middle;i>=left;i--)
{
lefts += a[i];
}
if(lefts>s1)
{
s1=lefts;
}
int s2=0;
int rights=0;
for(int i=middle;i<=right;i++)
{
rights += a[i];
}
if(right>s1)
{
s2=rights;
}
sum = s1+s2;
if(sum<leftsum)
{
sum = leftsum;
}
if(sum<rightsum)
{
sum=rightsum;
}
return sum;
}
}
二.分析时间复杂度
首先吐槽一下,为什么我没复习看书就跑去做pta作业第四题,自己写了一个算法,最后发现没用上递归,一看书,醍醐灌顶。
首先这个问题分为三种情况:
1.直接就是在中间取得这个子段,比如pta中的例题所给数据
6(数据长度)
-2 11 -4 13 -5 -2
这个最大子段很明显是 11 -4 13 和为20
一开始我写的就是赋两个指针,然后一个left往后指(最大值为mid),一个right(最小值为mid+1),赋值为n往前指,然后记录最大值并输出就可以了,然而,这样的结果是,忽略了左边或者右边全为负数或者和为负数的情况。在这里记录一下自己探索出来的但是失败的代码。
#include<iostream>
using namespace std;
int main()
{
int flag=0;
int leftsum=0;
int rightsum=0;
int n;
cin>>n;
int a[10001];
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(a[i]>0)
{
flag=1;
}
}
for(int i=1;i<=n/2;i++)
{
leftsum+=a[i];
rightsum+=a[i + n/2];
}
```c++
int maxleftsum=leftsum;
int maxrightsum=rightsum;
int MAXleft=leftsum;
int MAXright=rightsum;
for(int i=1;i<=n/2;i++)
{
maxleftsum-=a[i];
if(maxleftsum > leftsum && maxleftsum > MAXleft)
{
MAXleft=maxleftsum;
}
}
for(int j=n;j>n/2;j--)
{
maxrightsum-=a[j];
if(maxrightsum > rightsum && maxrightsum > MAXright)
{
MAXright=maxrightsum;
}
}
if(flag==0)
{
cout<<0;
}
else if(MAXleft>0&&MAXright>0)
{
cout<<MAXleft+MAXright;
}
else if(MAXleft<0)
{
cout<<MAXright;
}
else
{
cout<<MAXleft;
}
```
}
2.第二种情况
根据上面的分析,分治想法是好的,但仅仅对原数据对半切开,显然只能做到符合题意中的数据。最重要的原因是,缺少递归调用该算法。
第二种情况就是,左段有一串最大子段,甚至有可能只有一个正数,递归调用获取就是(左段的左段....)。即:a[1:n] 最大子段和a[1:n/2]最大子段相同。
3.第三种情况
右段存在最大子段,和第二种情况类似,只是在右边,不再赘述。
然后我们可以发现,这三种情况符合典型的分治递归,即要不你就O(1)直接找到,要不你就接着递归去找,即T(n)=2T(n/2)+O(n)。 按照次数来说,就是一段中的一半的一段再一半的一段......
所以最终时间复杂度是O(nlogn),个人的理解就是,递归就是logn,n是对每个元素进行操作,所以要乘上去,其实还是用那个主定理公式去解比较合理。
三、分治法思考
分治,字面上的解释是 分而治之,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。当求解一个问题规模很大很难直接求解,但是规模较小的时候问题很容易求解并且这个问题并且问题满足分治算法的适用条件,那么就可以使用分治算法。
二分搜索是最开始接触到的分治思想,然后还有比较经典的归并排序、快速排序,其实都是将大问题变成独立求解的小问题。(破防了,想起我之前追求的一个女生,和她一起玩悬疑游戏里面有汉诺塔。)但是也并不是所有这样的问题都一定要分治,这种分的思想也适合于平时学习考试,每个都拆点,大事化小,虽然每个子问题都可能不相同,但是独立的去做,会比直接拿一块大东西来更好完成。