使用分治思想求解最大子序列
本文使用分治思想求解一个整型数组中的最大子序列,该算法的时间复杂度为NlogN,使用千万级的数据量计算结果的时间不超过0.5s。该算法使用了分治的思想:求解最大子序列的问题可以理解为将整个数组分成左右两部分,分别求解左边和 右边的最大子序列,并且还有一种情况是最大子序列在中间,此时可以可以直接从中间开始分别向左和向右遍历求解左右两边的最大子序列(由于此时假定最大子序列在中间,因而中间的元素肯定在最大子序列中),然后将两边的最大子序列相加就会得到最大子序列在中间时的子序列,此时当前数组就会有三个(左边,右边和中间)已经求得的最大子序列,现只需要比较这三个子序列的和即可,将最大和返回。具体的算法如下:
public class Solution { public long findMaxSubSequence(Integer[] arr) { // return maxSumRec(arr, 0, arr.length - 1); } // 求解最大子序列函数 private long maxSumRec(Integer[] arr, int left, int right) { // 递归调用的出口 if (left == right) { return arr[left]; } // 分别计算左边和右边的最大子序列 int center = (left + right) / 2; long maxLeftSum = maxSumRec(arr, left, center); long maxRightSum = maxSumRec(arr, center + 1, right); // 计算中间的最大子序列的左半部分的最大值 int maxLeftBorderSum = 0, leftBorderSum = 0; for (int i = center; i >= left; i--) { leftBorderSum += arr[i]; if (leftBorderSum > maxLeftBorderSum) { maxLeftBorderSum = leftBorderSum; } } // 计算中间的最大子序列的右半部分的最大值 int maxRightBorderSum = 0, rightBorderSum = 0; for (int i = center + 1; i <= right; i++) { rightBorderSum += arr[i]; if (rightBorderSum > maxRightBorderSum) { maxRightBorderSum = rightBorderSum; } } return max(maxLeftSum, maxRightSum, maxLeftBorderSum + maxRightBorderSum); } // 求解三个值中的最大值 private long max(long maxLeftSum, long maxRightSum, int maxBorderSum) { return maxLeftSum >= maxRightSum && maxLeftSum >= maxBorderSum ? maxLeftSum : (maxRightSum > maxBorderSum ? maxRightSum : maxBorderSum); } }
具体的实验程序如下:
import java.util.Date; import java.util.Random; public class App { public static void main(String[] args) { Integer[] arr = new Integer[10000000]; for (int i = 0; i < 10000000; i++) { arr[i] = new Random().nextInt(); } Solution solution = new Solution(); Long start = new Date().getTime(); long result = solution.findMaxSubSequence(arr); Long end = new Date().getTime(); System.out.println("结果为:" + result); System.out.print("所用时长为:" + (end - start)); } }
运行结果如下:
计算结果为:2147483164 所用时长为:447 Process finished with exit code 0
这是计算最大子序列的一种算法,现贴出一种更为完美的方法,其时间复杂度为O(N),代码量也得到了大大的简化,代码如下:
public class Solution { public long findMaxSubSequence(Integer[] arr) { long maxSum = 0, thisSum = 0; for (int i = 0; i < arr.length; i++) { thisSum += arr[i]; if (thisSum > maxSum) { maxSum = thisSum; } else if (thisSum < 0){ thisSum = 0; } } return maxSum; } }
由于本人也不甚理解,现只将代码帖于此处。