《算法导论》的第四章:分治策略中提到了最大子数组问题。采用分治策略可以得到一个渐进复杂性优于暴力解法的算法。文中使用Java实现该算法。
问题:你被许可可以在某一时刻买进某公司的股票,并在之后某个日期将其卖出,买进卖出都是在当天交易结束后进行。为了补偿这一限制,你可以了解股票将来的价格。你的目标是最大化收益。股票价格变化如下表:
天 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
价格 | 100 | 113 | 110 | 85 | 105 | 102 | 86 | 63 | 81 | 101 | 94 | 106 | 101 | 79 | 94 | 90 | 97 |
变化 | —— | 13 | -3 | -25 | 20 | -3 | -16 | -23 | 18 | 20 | -7 | 12 | -5 | -22 | 15 | -4 | 7 |
用Java实现算法,代码如下:
public class Subarray {
//如果最大子数组横跨左右部分数组
public static int[] FindMaxCrossingSubarray(int[] A, int low, int mid, int high) {
int[] result = new int[3];
//从中间点向左遍历,找出左半部分过中点的最大子数组
int sum = 0;
int i;
for (i=mid;i>=low;i--) {
sum = sum + A[i];
if (sum>result[2]) {
result[2] = sum;
result[0] = i;
}
}
//从中间往右遍历,找出右半部分过中点的最大子数组
sum = 0;
result[2] = 0;
for (i=mid;i<=high;i++) {
sum = sum + A[i];
if (sum>result[2]) {
result[2] = sum;
result[1] = i;
}
}
//将左右两个子数组组合
result[2] = 0;
for (i = result[0];i<=result[1];i++) {
result[2] = result[2] + A[i];
}
return result;
}
//将数组分成左右两个部分,依次计算左数组、右数组的最大子数组,再计算横跨左右部分的中间子数组,选择最大的输出
public static int[] FindMaximumSubarray(int[] A, int low, int high) {
int[] result = new int[3];
int[] result_left = new int[3];
int[] result_right = new int[3];
int[] result_cross = new int[3];
int mid = (int)(low+high)/2;
//基本情况:数组中只有一个元素,则返回该数组
if(low==high) {
result[0]=low;
result[1]=high;
result[2]=A[low];
return result;
}
//递归情况:数组中多于一个元素,依次计算三种情况下的最大子数组
else {
result_left = FindMaximumSubarray(A, low, mid);
result_right = FindMaximumSubarray(A, mid+1, high);
result_cross = FindMaxCrossingSubarray(A, low, mid, high);
//比较三种情况的最大子数组,选择最大的输出
if (result_left[2]>result_right[2] && result_left[2]>result_cross[2]) {
return result_left;
}
else if (result_right[2]>result_left[2] && result_right[2]>result_cross[2]) {
return result_right;
}
else {
return result_cross;
}
}
}
public static void main(String[] args) {
int[] result = new int[3];
int[] A = {13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7};
result = FindMaximumSubarray(A, 0, 15);
System.out.print("The Maximum Subarray is : ");
for(int i=result[0]; i<=result[1];i++) {
System.out.print(A[i]+" ");
}
System.out.print("\nThe sum of the subarray is : "+result[2]);
}
}
运行结果:
The Maximum Subarray is : 18 20 -7 12
The sum of the subarray is : 43