[算法导论]分治法---最大子数组
来源:互联网 发布:苹果好软件推荐 编辑:程序博客网 时间:2024/04/29 22:53
分治策略---最大自子数组
一、分治策略的三个步骤
1、分解:将问题划分为一些子问题,子问题的形式与原问题一样,只是规模更小
2、解决:递归地求解出子问题。如果子问题的规模足够小,则停止递归,直接求解。
3、合并:将子问题的解组合成原问题的解。
二、最大子数组问题
题目描述:给定义数组A,长度为n,找出数组A中的最大子数组,例如数组A={-23,18,20,-7,12},则最大子数组为{18,20,-7,12}。
使用分治策略的求解方法:假定我们要寻找子数组A[low...high]的最大子数组,使用分治法意味着我们要将子数组划分为两个规模尽可能相等的子数组。也就是说,找到子数组的中央位置,比如mid,然后求解两个子数组A[low...mid]和A[mid + 1...high]。所以可以知道,A[low...high]的任何连续子数组A[i...j]所处的位置必然是三种情况之一:
1)完全位于子数组A[low...mid]中, 因此low<=i<=j<=mid;
2)完全位于子数组A[mid + 1...high]中,因此mid<=i<=j<=high;
3)跨越了中点,因此low<=i<=mid<j<=high;
实际上,A[low...high]的一个最大子数组必然是以上三种情况中的所有子数组中和的最大者。所以,我们可以递归地求解A[low...mid]和A[mid + 1...high]的最大字数组,然后在三者中选取和最大者。
我们可以很容易地在线型时间内求出跨越中点的最大子数组,因为它加入了限制---必须跨越中点,所以以下算法可返回跨越中点的最大子数组的和:
int Find_Max_Crossing_SubArray(int A[], int low, int mid, int high){ int left_sum = -0xff; int sum = 0; for (int i = mid; i >= low; i --) { sum += A[i]; if (sum >left_sum) { left_sum = sum; } } int right_sum = -0xff; sum = 0; for (int j = mid + 1; j <= high; j ++) { sum += A[j]; if (sum > right_sum) { right_sum = sum; } } return left_sum + right_sum;}
有了一个线型时间的Find_Max_Crossing_SubArray()在手,我们就可以设计出求解最大子数组问题的分治算法代码了:
int Find_Maximum_SubArray(int A[], int low, int high){ int left_sum, right_sum, cross_sum; if (high == low) { return A[low]; } else { int mid = (low + high) / 2; left_sum = Find_Maximum_SubArray(A, low, mid); right_sum = Find_Maximum_SubArray(A, mid + 1, high); cross_sum = Find_Max_Crossing_SubArray(A, 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; } }}
三、算法分析
建立一个递归式来描述递归过程Find_Maximum_SubArray( )运行时间, 用T(n)表示Find_Maximum_SubArray( )求解n个元素的最大字数组的运行时间。因为前8行均为常量时间,所以T(1) = O(1). 第9和第10行给总的运行时间增加了2T(n/2)。第11行调用Find_Max_Crossing_SubArray( )花费O(n)的时间。因此对于递归情况,我们有:
T(n) = 2T(n/2) + O(n);
所以我们可以得到Find_Maximum_SubArray( )的运行时间T(n)的递归式:
T(n) = O(1)n = 1
T(n) = 2T(n/2) + O(n)n > 1
所以时间复杂度为O(nlg n);
四、完整代码
#include <iostream>using namespace std;int Find_Max_Crossing_SubArray(int A[], int low, int mid, int high){ int left_sum = -0xff; int sum = 0; for (int i = mid; i >= low; i --) { sum += A[i]; if (sum >left_sum) { left_sum = sum; } } int right_sum = -0xff; sum = 0; for (int j = mid + 1; j <= high; j ++) { sum += A[j]; if (sum > right_sum) { right_sum = sum; } } return left_sum + right_sum;}int Find_Maximum_SubArray(int A[], int low, int high){ int left_sum, right_sum, cross_sum; if (high == low) { return A[low]; } else { int mid = (low + high) / 2; left_sum = Find_Maximum_SubArray(A, low, mid); right_sum = Find_Maximum_SubArray(A, mid + 1, high); cross_sum = Find_Max_Crossing_SubArray(A, 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; } }}int main(){ int A[100]; int n; cout<<"Please input the number of numbers:"; cin>>n; for (int i = 0; i < n; i ++) { cin>>A[i]; } cout<<"最大子序列的和为:"<<Find_Maximum_SubArray(A, 0, n - 1)<<endl; return 0;}
- [算法导论]分治法---最大子数组
- 算法导论,分治策略,最大子数组
- 最大子数组问题(分治法)--【算法导论】
- 「算法导论」:分治法求最大子数组
- 算法导论_最大子数组问题(分治策略)
- 算法导论_最大子数组问题(分治策略)
- 算法导论 分治1 最大子数组和
- 算法导论:分治策略__最大子数组问题
- 算法导论-----分治策略----------求最大子数组
- 算法导论之分治策略:最大子数组问题
- 算法导论学习:分治策略之最大子数组问题
- 算法导论-求最大子数组-分治策略 c++版本
- 分治之最大子数组-《算法导论》学习笔记四
- 算法导论 最大子数组问题(分治策略)
- 算法导论--分治策略求解最大子数组问题
- 算法导论——分治法——最大子数组问题
- 算法导论-分治、最大子序列问题
- 算法导论-分治、最大子序列问题
- 计算机视觉、机器学习相关领域论文和源代码大集合--持续更新……
- Having
- ios面试题整理
- OpenJTAG与Jlink/J-link的区别
- Java中Calendar的一些简单操作 及 JS中获取当前时间前一天时间(js中时间Date操作)
- [算法导论]分治法---最大子数组
- JSTL与Struts2标签的使用对比 (转)
- ubuntu and windows 7 setting two displays
- 黑话管理:偶像
- plsql developer导出csv乱码问题
- IO流4及总结
- Hadoop2.0 配置详解
- 【SPOJ KQUERY】【HDU 4417】静态区间rank查询
- 数据库有用网站