分治算法实现最大连续子数组和

之前在《编程之美》上看到过这道题,可以使用动态规划在O(n)时间内解出。
这篇日记给出一个性能略低,时间复杂度略高(nlogn),代码略麻烦的分治算法。(因为之前没见过这个算法,只看过动态规划和暴力求解,所以昨天晚上看到后就实现了下,还是推荐大家使用动态规划)
问题描述:在一个数组a[0,,,,n]中,找出一段连续子数组a(n1,n2,,,nk),使得这段连续子数组和最大。
分治法:求一个数组a[low,high]的最大子数组,只有3种情况:
1 该子数组位于a[low,high]的左边,即位于a[low,mid]中,则可以递归的求解a[low,mid].
2 该子数组位于a[low,high]的右边,即位于a[mid+1,high]中,则可以递归的求解a[mid+1,high].
3 该子数组位于a[low,high]的中间,即包括了a(mid),则直接从中间求解中间向左右延伸的最大子数组和,详见getMiddle函数。
4 返回上面三种情况的最大值,则是我们要求解的答案。
代码:
  1. int function(int a[], int low, int high);
  2. int getMiddle(int a[],int low,int high);

  3. int _tmain(int argc, _TCHAR* argv[])
  4. {
  5. //函数调用中,传入的参数low和high假设都是可以下标访问的
  6. //即最外层low=0 high=n-1
  7. int a[10]={-1,2,9,1,-13,-12,-14,1,10,-4};
  8. printf("%d",function(a,0,9));
  9. return 0;
  10. }

  11. int function(int a[], int low, int high)
  12. {
  13. if(low==high)
  14. return a[low];
  15. else 
  16. {
  17. int mid=(low+high)/2;
  18. int left=function(a,0,mid);//最大和在左边,递归调用
  19. int right=function(a,mid+1,high);//最大和在右边,递归调用
  20. int middle=getMiddle(a,low,high);//最大和在中间的左右连续一段,调用getMiddle()
  21. if(middle>left && middle>right)
  22. return middle;
  23. else if(left>middle && left>right)
  24. return left;
  25. else
  26. return right;
  27. }
  28. }
  29. int getMiddle(int a[],int low,int high)
  30. {
  31. int mid=(low+high)/2;
  32. int left_max=-999;
  33. int right_max=-999;
  34. int sum=0;
  35. for(int i=mid;i>=low;i--)//计算左边的最大和
  36. {
  37. sum+=a[i];
  38. if(sum>left_max)
  39. left_max=sum;
  40. }
  41. sum=0;
  42. for(int i=mid+1;i<=high;i++)//计算右边的最大和
  43. {
  44. sum+=a[i];
  45. if(sum>right_max)
  46. right_max=sum;
  47. }
  48. return right_max+left_max;
  49. }
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值