算法笔记四:使用分治策略求最大子数组算法
来源:互联网 发布:淘宝企业店铺怎么申请 编辑:程序博客网 时间:2024/05/17 04:23
算法思想:
//求最大子数组问题:给定一个数组,求出值相加起来的最大的子数组
//当数组中全部是正数时,数组本身就是其最大子数组
//采取分治策略来解答,将数组一分为二,那么,答案要么位于左侧,要么位于右侧,要么横跨分割点。
//横跨分割点时,其解答的代价是线性的
//左侧和右侧又可以采用递归方式继续求解
//不难得出,代价为O(NlgN)
//跟传统的依次求每种可能的代价O(n^2)有非常明显的性能改进
分解—>解决—>合并
在解决的步骤中,什么条件下是阻止其继续分解的终止阀呢?:
分解的只有一个元素了
解决:
限制到最大数组必须横跨中间点,这是一个线性的过程,所以,就将原问题,分解成了N个子规模的线性问题
合并:
这里的合并,代价可以忽略,只需要比较下左区间和右区间以及横跨点区间的最大值即可
最好情况:
与最坏情况相同,都是O(n*log2n)
最坏情况:
与最好情况相同,都是
O(n*log2n)
下面我们来分析下为什么最好情况和最坏情况都是一样的,都为O(n*log2n)
分解:
对规模为N的数据,其分解过程,就是找到一个分解点X,所以其分解代价为常量O(1)
合并:
合并的过程,就是几个比较,O(1)
解决:
n个元素的顺序遍历求和过程,线性代价,O(n)
一样的使用递归树方法,不难得出最终的代价为n*log2n
算法实现:
#ifndef __p1__MaxSubArray__#define __p1__MaxSubArray__#include <stdio.h>//求最大子数组问题:给定一个数组,求出值相加起来的最大的子数组//当数组中全部是正数时,数组本身就是其最大子数组//采取分治策略来解答,将数组一分为二,那么,答案要么位于左侧,要么位于右侧,要么横跨分割点。//横跨分割点时,其解答的代价是线性的//左侧和右侧又可以采用递归方式继续求解//不难得出,代价为O(NlgN)//跟传统的依次求每种可能的代价O(n^2)有非常明显的性能改进class MaxSubArray { public: //分解 void split(int * data,int left,int right,int * rLeft,int * rRight,int * rSum){ //分解的终点,就是数组只有一个元素,那么,最大数组就是数组本身 if(left == right){ *rLeft = left; *rRight = left; *rSum = *(data + left); return; } //求出中间分割点 int middle = (left + right) / 2; //解决无限递归问题,区间只有两个元素 int p_start1 = middle; int p_start2 = middle; if(middle == left || middle == right){ p_start1 = left; p_start2 = right; } int rleft1,rright1,rsum1,rleft2,rright2,rsum2,rleft3,rright3,rsum3; //求左边的最大子数组 split(data, left, p_start1, &rleft1, &rright1, &rsum1); //求跨越点的最大子 subArrayAcrossingPoint(data,left,right,middle,&rleft2,&rright2,&rsum2); //求右边的最大子数组 split(data, p_start2, right, &rleft3, &rright3, &rsum3); if(rsum1 >= rsum2 && rsum1 >= rsum3){ //左侧最大 *rLeft = rleft1; *rRight = rright1; *rSum = rsum1; }else if (rsum2 >= rsum1 && rsum2 >= rsum3){ //横跨点大 *rLeft = rleft2; *rRight = rright2; *rSum = rsum2; }else{ //右侧大 *rLeft = rleft3; *rRight = rright3; *rSum = rsum3; } } //解决 void subArrayAcrossingPoint(int * data,int left,int right,int accrossingPoint,int * rLeft,int * rRight,int * rSum){ //这里理论上来说,应该用负无穷大来替代 int max_sum_left = -999999999, max_sum_right = -999999999; int tmp_sum = 0; for(int i = accrossingPoint;i >= left;i--){ tmp_sum = tmp_sum + *(data + i); if(tmp_sum > max_sum_left){ *rLeft = i; max_sum_left = tmp_sum; } } tmp_sum = 0; for(int i = accrossingPoint + 1;i <= right;i++){ tmp_sum = tmp_sum + *(data + i); if(tmp_sum > max_sum_right){ *rRight = i; max_sum_right = tmp_sum; } } *rSum =max_sum_left +max_sum_right; } //排序入口 void doing(int * data,int size,int * rLeft,int * rRight,int * rSum){ split(data,0,size - 1,rLeft,rRight,rSum); }};#endif /* defined(__p1__MaxSubArray__) */
算法总结:
该算法在应对数据规模增长的表现上,logn明显好于传统的每个组合都求值的n^2,
空间代价上,无论是分解还是合并,都不需要另辟空间
0 0
- 算法笔记四:使用分治策略求最大子数组算法
- 算法导论-----分治策略----------求最大子数组
- 算法导论-求最大子数组-分治策略 c++版本
- 算法导论,分治策略,最大子数组
- 分治之最大子数组-《算法导论》学习笔记四
- [算法导论-分治策略]求最大子数组之各种解法及源代码实现
- 算法导论_最大子数组问题(分治策略)
- 算法导论_最大子数组问题(分治策略)
- 算法导论:分治策略__最大子数组问题
- 算法学习之分治策略-最大子数组
- 算法导论之分治策略:最大子数组问题
- 算法导论学习:分治策略之最大子数组问题
- 算法导论 最大子数组问题(分治策略)
- 算法导论--分治策略求解最大子数组问题
- 用分治策略求最大子数组
- 分治策略求最大子数组
- 最大子数组-分治算法
- 分治算法--最大子数组
- aaa
- mysql binary log 操作
- Unity3D研究院之Unity中连接本地或局域网MySQL数据库(五十九)
- div高度不自适应,溢出的一种解决办法
- 链表加锁的操作方式
- 算法笔记四:使用分治策略求最大子数组算法
- 使用c语言库函数-完成加减天数数后自动转换成相关日期
- php设计模式系列--委托模式
- 验证数字的正则表达式集
- ajax调用WebService服务
- ios&java 常用加密(一)
- SSH原理与运用(一):远程登录
- ubuntu9.04下用bochs安装及调试linux0.11内核
- ANDROID音频系统散记之二:resample