题目
假定你来交易某只股票。
你的每次买或卖都限定为1股。
你最多可进行4次交易(卖和卖各2次),
开始时,你手中无股票。
并且,必须等第一笔卖掉后,才能买第二笔。
每个时间点只能完成一次操作(买或卖)。
还要保证交易结束时,你手中无股票。
给出一天中的该股票价格序列,
请写一个程序计算可以获得的最大收益。
例如,序列是:
[10,22,5,75,65,80]
则返回值应为:87
分析
当然是先考虑最笨的办法。
逐一枚举 4 次操作的时间点,4 层循环嵌套。
两次收益求和,筛出最大值即可。
这里还要注意小陷阱,最多可操作4次,
也就是说,你可以操作 2 次,或 0 次。
当股价一路下滑的时候,你至少不要赔钱吧。
稍考虑一下这种解法,会发现存在许多重复的计算。
比如,当前一回合卖出点确定时,无论是什么时候买的,都与后一个回合的最大盈利无关了。
其实这个问题的优化与著名的《最大连续和》问题如出一辙。
只要准备几个数组,可以优化到 O(n) 的量级。
代码
先来个笨的。
注意最后别弄个负的盈利出来。
//problem007
public class A{
static int f(int[] data){
int res = 0;
for(int a=0; a<data.length; a++){
for(int b=a+1; b<data.length; b++){
int x = data[b]-data[a];
res = Math.max(res,x);
for(int c=b+1; c<data.length; c++){
for(int d=c+1; d<data.length; d++){
int y = data[d]-data[c];
res = Math.max(res,x+y);
}
}
}
}
return res;
}
public static void main(String[] args){
System.out.println(f(new int[]{10,22,5,75,65,80}));
System.out.println(f(new int[]{9,8,7,6,5,4,3,2,1}));
System.out.println(f(new int[]{1,2,3,4,5,6,7,8,9}));
System.out.println(f(new int[]{
486,465,489,482,462,459,476,485,476,464,456,476,484,505,515,499,501,514,537,549,
566,568,592,579,577,561,551,551,555,555,579,560,576,592,610,612,608,616,638,652,
659,636,621,604,613,611,610,626,620,641,628,605,627,635,621,645,660,672,695,694,
704,701,691,702,713,714,735,732,740,740,722,706,695,704,697,674,657,669,648,634,
626,640,643,648,639,661,677,698,693,710,722,705,699,697,708,699,684,667,646,661,
679,662,650,628,630,644,658,672,649,640,618,639,623,636,615,635,614,602,583,560,
536,558,558,554,564,552,531,548,556,567,559,535,559,568,552,571,553,560,547,531,
549,558,549,545,545,524,547,538,545,551,540,545,545,544,534,554,574,559,577,601,
590,590,607,600,608,586,599,622,618,607,590,591,603,585,571,551,539,515,522,531,
546,529,539,563,549,556,559,543,534,549,567,560,550,536,519,531,534,515,508,508,
490,472,455,474,476,465,486,509,509,510,493,481,499,492,489,497,512,516,527,550,
555,569,563,550,528,552,559,569,575,560,584,589,585,586,586,593,583,563,543,537,
535,514,524,526,517,530,537,546,541,545,554,572,578,556,532,532,513,491,487,483,
494,505,505,483,500,522,546,527,549,538,543,564,566,564,574,589,587,600,610,589,
596,612,628,614,638,619,629,635,638,659,643,629,637,624,619,628,651,671,694,697,
692,697,707,727,711,700,713,710,713,714,707,721,728,707,697,677,668,681,702,691,
699,718,720,710,697,695,678,681,704,718,728,731,733,748,746,754,741,736,721,736,
715,714,737,751,746,765,758,773,773,791,773,784,796,800,806,807,814,831,846,827,
827,810,830,821,842,841,824,824,810,821,821,816,799,811,808,799,777,800,782,781,
774,776,777,801,790,814,822,835,821,806,818,819,797,780,784,783,774,766,759,759,
755,746,743,719,716,694,713,711,696,704,705,718,712,715,739,749,737,737,716,700,
684,691,700,702,687,679,659,639,649,663,682,663,661,661,683,674,652,663,685,665,
659,677,676,661,678,697,692,704,719,710,723,742,760,776,752,747,741,741,741,762,
766,772,759,747,770,775,786,796,819,797,781,796,815,797,785,777,765,770,793,805,
788,775,780,758,745,735,727,748,761,737,716,733,723,702,682,679,687,689,702,693,}));
}
}
再来个O(n) 级的。以空间换时间了。
//problem007
public class B{
static int f(int[] data){
int[] min = new int[data.length];
min[0] = Integer.MAX_VALUE;
for(int i=1; i<data.length; i++){
min[i] = Math.min(min[i-1],data[i-1]);
}
int[] best_a = new int[data.length];
best_a[0] = 0;
for(int i=1; i<data.length; i++){
best_a[i] = Math.max(best_a[i-1],data[i]-min[i]);
}
int[] max = new int[data.length];
max[max.length-1] = 0;
for(int i=max.length-2; i>=0; i--){
max[i] = Math.max(max[i+1],data[i+1]);
}
int[] best_b = new int[data.length];
best_b[best_b.length-1] = 0;
for(int i=best_b.length-2; i>=0; i--){
best_b[i] = Math.max(best_b[i+1], max[i]-data[i]);
}
int res = 0;
for(int i=0; i<data.length; i++){
if(i==data.length-1)
res = Math.max(res, best_a[i]);
else
res = Math.max(res, best_a[i]+best_b[i+1]);
}
return res;
}
public static void main(String[] args){
System.out.println(f(new int[]{10,22,5,75,65,80}));
System.out.println(f(new int[]{9,8,7,6,5,4,3,2,1}));
System.out.println(f(new int[]{1,2,3,4,5,6,7,8,9}));
System.out.println(f(new int[]{
486,465,489,482,462,459,476,485,476,464,456,476,484,505,515,499,501,514,537,549,
566,568,592,579,577,561,551,551,555,555,579,560,576,592,610,612,608,616,638,652,
659,636,621,604,613,611,610,626,620,641,628,605,627,635,621,645,660,672,695,694,
704,701,691,702,713,714,735,732,740,740,722,706,695,704,697,674,657,669,648,634,
626,640,643,648,639,661,677,698,693,710,722,705,699,697,708,699,684,667,646,661,
679,662,650,628,630,644,658,672,649,640,618,639,623,636,615,635,614,602,583,560,
536,558,558,554,564,552,531,548,556,567,559,535,559,568,552,571,553,560,547,531,
549,558,549,545,545,524,547,538,545,551,540,545,545,544,534,554,574,559,577,601,
590,590,607,600,608,586,599,622,618,607,590,591,603,585,571,551,539,515,522,531,
546,529,539,563,549,556,559,543,534,549,567,560,550,536,519,531,534,515,508,508,
490,472,455,474,476,465,486,509,509,510,493,481,499,492,489,497,512,516,527,550,
555,569,563,550,528,552,559,569,575,560,584,589,585,586,586,593,583,563,543,537,
535,514,524,526,517,530,537,546,541,545,554,572,578,556,532,532,513,491,487,483,
494,505,505,483,500,522,546,527,549,538,543,564,566,564,574,589,587,600,610,589,
596,612,628,614,638,619,629,635,638,659,643,629,637,624,619,628,651,671,694,697,
692,697,707,727,711,700,713,710,713,714,707,721,728,707,697,677,668,681,702,691,
699,718,720,710,697,695,678,681,704,718,728,731,733,748,746,754,741,736,721,736,
715,714,737,751,746,765,758,773,773,791,773,784,796,800,806,807,814,831,846,827,
827,810,830,821,842,841,824,824,810,821,821,816,799,811,808,799,777,800,782,781,
774,776,777,801,790,814,822,835,821,806,818,819,797,780,784,783,774,766,759,759,
755,746,743,719,716,694,713,711,696,704,705,718,712,715,739,749,737,737,716,700,
684,691,700,702,687,679,659,639,649,663,682,663,661,661,683,674,652,663,685,665,
659,677,676,661,678,697,692,704,719,710,723,742,760,776,752,747,741,741,741,762,
766,772,759,747,770,775,786,796,819,797,781,796,815,797,785,777,765,770,793,805,
788,775,780,758,745,735,727,748,761,737,716,733,723,702,682,679,687,689,702,693,}));
}
}
详解
先去看《最大连续和》问题,看懂了再看这个。应该没难度。
实在看不下去,还可以看笔者在“千聊”上解答。
“千聊”上搜同样标题即可。
或者手机扫下图加关注。