算法导论第三版第四章 最大子数组和的三种解法(暴力、教材分治法、线性解法)
来源:互联网 发布:淘宝网管控记录 编辑:程序博客网 时间:2024/05/17 03:23
1.暴力求解法
该方法的思想非常简单,先找出从第1个元素开始的最大子数组,而后再从第2个元素开始找出从第2个元素开始的最大子数组,依次类推,比较得出最大的子数组。实现代码如下:
/* 常规方法,时间复杂度O(n*n) 先从第一个元素开始向后累加, 每次累加后与之前的和比较,保留最大值, 再从第二个元素开始向后累加,以此类推。 */ int MaxSubSum1(int *arr,int len) { int i,j; int MaxSum = 0; //每次开始累加的起始位置的循环 for(i=0;i<len;i++) { int CurSum = 0; //向后累加的循环 for(j=i;j<len;j++) { CurSum += arr[j]; if(CurSum > MaxSum) MaxSum = CurSum; } } return MaxSum; }显然时间复杂度为O(n*n)。
2.教材分治法
使用分治技术意味着我们要将子数组划分为两个规模尽量相等的子数组。也就是说,找到子数组的中央位置,比如mid,然后考虑求解两个子数组array[low...mid]和array[mid+1...high]。可知array[low...high]的任何连续子数组array[i...j]所处的位置必然是以下三种情况之一:
(1)完全位于子数组array[low...mid]中,因此low<=i<=j<=mid.
(2)完全位于子数组array[mid+1...high]中,因此mid<i<=j<=high.
(3)跨越了中点,因此low<=i<=mid<j<=high.
三种情况中选取和最大者返回即可,代码如下:
#include<iostream>using namespace std;int Find_max_crossing_subarray(int array[], int low, int mid, int high){int left_sum = -10000,right_sum=-10000,sum=0,max_left,max_right;for (int i = mid; i >= low; i--){sum += array[i];if (sum > left_sum) { left_sum = sum; max_left = i; }}sum = 0;for (int j = mid + 1; j <= high; j++){sum += array[j];if (sum > right_sum){right_sum = sum;max_right = j;}}return left_sum + right_sum;}int Find_max_subarray(int array[], int low, int high){int mid,left_sum,right_sum,cross_sum;if (high == low){return array[low];}else {mid = (low + high) / 2;left_sum = Find_max_subarray(array,low,mid);right_sum = Find_max_subarray(array,mid+1,high);cross_sum = Find_max_crossing_subarray(array,low,mid,high);}if (left_sum >= right_sum&&left_sum >= cross_sum) return left_sum;else if (right_sum >= left_sum&&right_sum >= cross_sum) return right_sum;else return cross_sum;}void main(){int array[] = { 1,-2,3,10,-4,7,2,-19,2 };int sum = Find_max_subarray(array,0,8);cout <<"最大子数组的和为:"<<sum << endl;system("pause");}通过主方法求解算法递归式得到时间复杂度为O(nlog(n)).
3.线性复杂度方法
该算法在每次元素累加和小于0时,从下一个元素重新开始累加。代码如下:
#include<iostream>#include<stdlib.h>using namespace std;//求最大连续子序列和int FindGreatestSumOfSubArray(int arry[],int len){ if(arry==NULL||len<=0) return -1; int start=0,end=0;//用于存储最大子序列的起点和终点 int p=0;//指针,用于遍历数组。 int currSum=0;//保存当前最大和 int greatestSum=-10000;//保存全局最大和 for(int i=0;i<len;i++) { if(currSum<0)//如果当前最大和为负数,则舍弃前面的负数最大和,从下一个数开始计算 { currSum=arry[i]; p=i; } else currSum+=arry[i];//如果当前最大和不为负数则加上当前数 if(currSum>greatestSum)//如果当前最大和大于全局最大和,则修改全局最大和 { greatestSum=currSum; start=p; end=i; } } cout<<"最大子序列位置:"<<start<<"--"<<end<<endl; return greatestSum;}void main(){ //int arry[]={1,-2,3,10,-4,7,2,-5}; int arry[]={1,-2,3,10,-4,7,2,-19,2}; int len=sizeof(arry)/sizeof(int); //cout<<len<<endl; int sum= FindGreatestSumOfSubArray(arry,len); cout<<"最大子序列和:"<<sum<<endl; system("pause");}可见时间复杂度为O(n),其中,
(1)p为一个遍历用于保存遍历数组中发现的最大和的起始,原来的start和end只用于保存真是的开始于结尾
(2)当currSum<0的时候,我们只让p值为最大和子数组的开始
(3)在最后判断currSum>greatestSum的时候,只有当currSum>greatestSum成立,才让start=p,否则就表明以p开头的子数组最大和不是最大的。
阅读全文
1 0
- 算法导论第三版第四章 最大子数组和的三种解法(暴力、教材分治法、线性解法)
- 算法导论-----最大子数组问题(线性解法)
- 算法导论第三版第六章 合并K个有序链表的三种解法(最小堆法和分治递归法)
- 算法导论第四章:最大子数组—递归,暴力和线性算法
- 算法导论-----最大子数组(归并解法)
- 最大子数组(暴力求解法)
- [算法导论-分治策略]求最大子数组之各种解法及源代码实现
- 最大子段和:线性序列的最大子段和的三种解法
- 用暴力求解法和分而治之法求解最大子数组问题的Java代码实现
- 最大子数组问题的三种方法:分治法、暴力法和非递归方法
- [算法导论]分治法---最大子数组
- 获得连续子数组的最大和(见算法导论第三版第三章)
- 求最大子数组的和,算法导论之分治递归求解,暴力求解,记忆扫描方法。
- 最大子数组问题的线性解法-wikipedia
- 最大子数组问题(分治法)--【算法导论】
- 最大子段分治法解法
- 算法导论第四章(数组的连续最大和)
- 算法导论-第四章-分治策略:最大子数组C++实现
- ACM题目百钱百鸡-N钱N鸡
- MySQL查看当前数据库
- 环形队列串口发送接收数据
- 经过漫长的试验,我终于写成一个简单的快速排序程序了。
- qt url下载链接 获取文件名
- 算法导论第三版第四章 最大子数组和的三种解法(暴力、教材分治法、线性解法)
- windows下storm ui显示用到的一点点控制台命令
- 工具类:根据URL获取短链接,根据短链接获取真实URL
- JavaWeb基础(3)—— JavaWeb 开发基础知识
- JAVA设计模式——享元模式
- myeclipse安装后配置
- 集合(链表和数组的区别)
- JAVA 基础知识 常用类
- 机器学习算法之线性回归