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

之前在《编程之美》上看到过这道题,可以使用动态规划在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. }

你可能感兴趣的:(算法)