股票两回合(算法入门题目007)

这是一篇关于股票交易算法的入门文章,探讨如何在限定4次交易操作的情况下,通过优化策略找到最大收益。首先从最直观的4层循环嵌套解法入手,然后分析并优化至线性复杂度的解决方案,与最大连续和问题相联系。文章提供两种代码实现,并鼓励读者深入理解相关问题,同时提供了在线讲解资源作为辅助学习。

题目

假定你来交易某只股票。
你的每次买或卖都限定为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,}));
	}
}

详解

先去看《最大连续和》问题,看懂了再看这个。应该没难度。
实在看不下去,还可以看笔者在“千聊”上解答。
“千聊”上搜同样标题即可。
或者手机扫下图加关注。

### 光流法C++源代码解析与应用 #### 光流法原理 光流法是一种在计算机视觉领域中用于追踪视频序列中运动物体的方法。它基于亮度不变性假设,即场景中的点在时间上保持相同的灰度值,从而通过分析连续帧之间的像素变化来估计运动方向和速度。在数学上,光流场可以表示为像素位置和时间的一阶导数,即Ex、Ey(空间梯度)和Et(时间梯度),它们共同构成光流方程的基础。 #### C++实现细节 在给定的C++源代码片段中,`calculate`函数负责计算光流场。该函数接收一个图像缓冲区`buf`作为输入,并初始化了几个关键变量:`Ex`、`Ey`和`Et`分别代表沿x轴、y轴和时间轴的像素强度变化;`gray1`和`gray2`用于存储当前帧和前一帧的平均灰度值;`u`则表示计算出的光流矢量大小。 #### 图像处理流程 1. **初始化和预处理**:`memset`函数被用来清零`opticalflow`数组,它将保存计算出的光流数据。同时,`output`数组被填充为白色,这通常用于可视化结果。 2. **灰度计算**:对每一像素点进行处理,计算其灰度值。这里采用的是RGB通道平均值的计算方法,将每个像素的R、G、B值相加后除以3,得到一个近似灰度值。此步骤确保了计算过程的鲁棒性和效率。 3. **光流向量计算**:通过比较当前帧和前一帧的灰度值,计算出每个像素点的Ex、Ey和Et值。这里值得注意的是,光流向量的大小`u`是通过`Et`除以`sqrt(Ex^2 + Ey^2)`得到的,再乘以10进行量化处理,以减少计算复杂度。 4. **结果存储与阈值处理**:计算出的光流值被存储在`opticalflow`数组中。如果`u`的绝对值超过10,则认为该点存在显著运动,因此在`output`数组中将对应位置标记为黑色,形成运动区域的可视化效果。 5. **状态更新**:通过`memcpy`函数将当前帧复制到`prevframe`中,为下一次迭代做准备。 #### 扩展应用:Lukas-Kanade算法 除了上述基础的光流计算外,代码还提到了Lukas-Kanade算法的应用。这是一种更高级的光流计算方法,能够提供更精确的运动估计。在`ImgOpticalFlow`函数中,通过调用`cvCalcOpticalFlowLK`函数实现了这一算法,该函数接受前一帧和当前帧的灰度图,以及窗口大小等参数,返回像素级别的光流场信息。 在实际应用中,光流法常用于目标跟踪、运动检测、视频压缩等领域。通过深入理解和优化光流算法,可以进一步提升视频分析的准确性和实时性能。 光流法及其C++实现是计算机视觉领域的一个重要组成部分,通过对连续帧间像素变化的精细分析,能够有效捕捉和理解动态场景中的运动信息
微信小程序作为腾讯推出的一种轻型应用形式,因其便捷性与高效性,已广泛应用于日常生活中。以下为该平台的主要特性及配套资源说明: 特性方面: 操作便捷,即开即用:用户通过微信内搜索或扫描二维码即可直接使用,无需额外下载安装,减少了对手机存储空间的占用,也简化了使用流程。 多端兼容,统一开发:该平台支持在多种操作系统与设备上运行,开发者无需针对不同平台进行重复适配,可在一个统一的环境中完成开发工作。 功能丰富,接口完善:平台提供了多样化的API接口,便于开发者实现如支付功能、用户身份验证及消息通知等多样化需求。 社交整合,传播高效:小程序深度嵌入微信生态,能有效利用社交关系链,促进用户之间的互动与传播。 开发成本低,周期短:相比传统应用程序,小程序的开发投入更少,开发周期更短,有助于企业快速实现产品上线。 资源内容: “微信小程序-项目源码-原生开发框架-含效果截图示例”这一资料包,提供了完整的项目源码,并基于原生开发方式构建,确保了代码的稳定性与可维护性。内容涵盖项目结构、页面设计、功能模块等关键部分,配有详细说明与注释,便于使用者迅速理解并掌握开发方法。此外,还附有多个实际运行效果的截图,帮助用户直观了解功能实现情况,评估其在实际应用中的表现与价值。该资源适用于前端开发人员、技术爱好者及希望拓展业务的机构,具有较高的参考与使用价值。欢迎查阅,助力小程序开发实践。资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值