数据结构——最大子序列和
2018-03-17 19:26
381 查看
最近我打算重温一遍数据结构,于是又遇到了求最大子序列和这一基本问题。记得之前我就没有明白透彻,这次便记录下来。 求最大子序列和,即求一个序列中,和值最大的连续子序列。首先采用暴力解法,即求出所有的子序列和,得到最大和,这个算法的时间复杂度是O(n^2)。
为什么这个算法的时间复杂度是O(n*logn)呢?因为长度N的子序列需花费时间是 T(N) = 2 * T(N/2) + cN 其中T(1) = O(1) 由此可推出, T(N) = 2 * ( 2 * T(N/4) + c*N/2 ) + cN = 4 * T(N/4) + 2cN .. .. T(N) = 2^n * O(1) + k*cN 其中 N / 2^k = 1
即 T(N) = 2 ^n * O(1) + N*logN
因此,分治法的时间复杂度是O(n*logn)。函数实现如下:
int MaxSubSum(int K, int a[]) //K是序列个数,用数组a存储 {//计算所有子序列的和 时间复杂度是O(n^2) int preSub, maxSubSum = 0; for (int i = 0; i < K; i++) { preSub = 0; for (int j = i; j < K; j++) { preSub += a[j]; if (preSub > maxSubSum) maxSubSum = preSub; } } return maxSubSum; }若是得到了时间复杂度O(n^2)的算法,我们得尝试优化到O(n*logn)。于是可以采用分治法,递归地解决这个问题——即把序列一分为二,分别递归求得左半边和右半边子序列最大和,再求出跨分界线子序列最大和,三者中的最大值即为所求,如下图所示:
为什么这个算法的时间复杂度是O(n*logn)呢?因为长度N的子序列需花费时间是 T(N) = 2 * T(N/2) + cN 其中T(1) = O(1) 由此可推出, T(N) = 2 * ( 2 * T(N/4) + c*N/2 ) + cN = 4 * T(N/4) + 2cN .. .. T(N) = 2^n * O(1) + k*cN 其中 N / 2^k = 1
即 T(N) = 2 ^n * O(1) + N*logN
因此,分治法的时间复杂度是O(n*logn)。函数实现如下:
int Max3(int x, int y, int z) //求三者中最大值 { int max; if (x > y) max = x; else max = y; if (z > max) max = z; return max; } int DivideAndConquer(int a[], int left, int right) {//分治法求数列 a[left]到 a[right]的最大子序列和 if (left == right) //子列中只有一个数字,则递归终止 { return a[left] > 0 ? a[left] : 0; } else { int centre = (left + right) / 2; //分界线 int maxLeftSum = DivideAndConquer(a, left, centre); //递归求左序列最大和 int maxRightSum = DivideAndConquer(a, centre + 1, right); //递归求右序列最大和 //下面求跨分界线的子序列最大和 int leftBorderSum = 0, rightBorderSum = 0; int maxLeftBorderSum = 0, maxRightBorderSum = 0; for (int i = centre; i >= left; i--) //往左依次扫描 { leftBorderSum += a[i]; if (leftBorderSum > maxLeftBorderSum) maxLeftBorderSum = leftBorderSum; } for (int i = centre + 1; i <= right; i++) //往右依次扫描 { rightBorderSum += a[i]; if (rightBorderSum > maxRightBorderSum) maxRightBorderSum = rightBorderSum; } return Max3(maxLeftSum, maxRightSum, maxLeft 9d10 BorderSum + maxRightBorderSum); } }最后,采用即时处理的算法,可以使时间复杂度降至O(n)。它的实现是:从输入的第一个数起,就进行累和,更新出现的最大和,若当前累和是负数,则弃之,从下一个数起重新累和。代码如下:
int MaxSubSum(int K) { int n, sum = 0, maxSum = 0; for (int i = 0; i < K; i++) { cin >> n; //输入一个数 sum += n; //累和 if (sum < 0) sum = 0; //若当前序列和为负,则弃之 else if (sum > maxSum) maxSum = sum; //更新最大和 } return maxSum; }至此,关于这道题的三种不同算法都介绍完了。通过此题,有助于我理解并分析时间复杂度,比较不同算法间的优劣。
相关文章推荐
- 求最大连续子序列之和的线性算法 c# 数据结构
- 数据结构与算法——给定整数A1,A2,....An,....(可能有负数),求该数据序列的最大子序列的和
- 数据结构——最大值最小化 (划分子序列)
- 求最大子序列问题-数据结构
- 【数据结构与算法】最大子序列
- 【数据结构与算法】最大子序列和问题的求解
- 数据结构之一(引论及最大子序列和问题)
- 【数据结构与算法】小于等于k的最大连续子序列和
- Kafka源码深度解析-序列12 -Server核心组件之2-ReplicaManager核心数据结构与Replica同步原理
- 动态规划——求最大公共子序列(一种可以求数据相似度匹配算法)
- 数据结构(C#)--二叉查找树的先序,中序,后序的遍历问题以及最大值,最小值,插入,删除
- NOJ 2024 入栈序列和出栈序列 数据结构理解
- 数据结构之---求最大字段和, 时间复杂度o(n)算法
- 数据结构——算法之(041)(寻找数组中的最大值和最小值)
- 数据结构实验之链表八:Farey序列
- 数据结构——链表之Farey序列
- 数据结构——算法之(020)( 和为n连续正数序列)
- ORACLE 监听配置,ORA-01086,事务,序列,savepoint,flashback,修改表数据和结构
- 数据结构实验之图论十:判断给定图是否存在合法拓扑序列
- 数据结构与算法——求最大子矩阵问题