前言
最近回溯算法,对以往算法和新学习算法进行一个系统的整理和学习,本文的最大子序列和的问题在很多算法书籍和技术文章中对此都有详述,个人简单整理仅为了再次消化和日后查阅,不喜误喷。个人理解,如有错误,欢迎指正。
注:本文中提及的时间复杂度均使用大O法。
问题描述
求-2,4,-1,5,6的最大子序列和
注:如果所有值都为负,则最大子序列和为0
方案一
- 思路:使用穷举的方式,使用for循环列出所有的子序列进行求和,每次进行对比并把大的数赋值给最大子序列和变量,总共使用三个for循环
注:i循环为从-2到6(头到尾),j循环为i到此序列size,k为计算此时i到此时j的子序列和 - 源码如下:
//穷举遍历法 三个for循环时间复杂度为n*n*n 十分低效
public static int maxSubSum1(int[] array) {
int maxSubSum = 0;
for (int i = 0; i < array.length; i++) {
for (int j = i; j < array.length; j++) {
int curSum = 0;
for (int k = i; k <= j; k++) {
curSum += array[k];
if (curSum > maxSubSum) {
maxSubSum = curSum;
}
}
}
}
return maxSubSum;
}
方案二
- 思路:maxSubSum1中k到j是前面加到后面求和,而这里是以i为指针基点,往后求和,减少一个for循环(k)时间复杂度为n*n
- 源码:
public static int maxSubSum2(int[] array) {
int maxSubSum = 0;
for (int i = 0; i < array.length; i++) {
//tmp 变量在上面for循环每次必须重新初始化
int tmpSum = 0;
for (int j = i; j < array.length; j++) {
//maxSubSum1中k到j是前面加到后面求和,而这里是以i为指针基点,往后求和
tmpSum += array[j];
if (tmpSum > maxSubSum) {
maxSubSum = tmpSum;
}
}
}
return maxSubSum;
}
方案三
- 思路
时间复杂度为nlogn的解法,使用分治策略和递归。主要把数组从中间分开,然后左边和右边递归求这两部分的最大子序列和,中间界限的最大子序列和为左边包含最接近中间的最大子序列和,以及右边包含最接近中间的最大子序列和的左右这两个最大子序列之和。最后比较这三部分的最大子序列和,其中最大的即为最大子序列和。时间复杂度为nlogn。 - 源码
/**
* 递归分治算法
* @param array
* @return
*/
//test (13/2 (6/2 ( 3/2 ( 1/2 ( 0 ) syso 1 ) syso 1 ) syso 0 ) ) syso 1