前沿–股票买卖(亚马逊面试题)
一.股票买卖
1.题目描述
设计一个算法,根据给定的股价走势信息,决定买入和卖出策略,该策略必须保证你的交易获得的利润最大化
2.暴力枚举法
检测任何一种可能的买卖组合.例如,第i买进,第j卖出,其中j>i,计算两者差价P(i,j)=S[j]-S[i],并返回计算得到的最大值
s=[10,4,8,7,9,6,2,5,3]
maxProfit=0
buyDay=0
sellDay=0
for i in range(len(s)-1):
for j in range(i+1,len(s)):
if s[j]-s[i]>maxProfit:
maxProfit=s[j]-s[i]
buyDay=i
sellDay=j
print("应该在第{0}天买入,第{1}天卖出,最大交易利润为:{2}".format(buyDay+1,sellDay+1,maxProfit))
应该在第2天买入,第5天卖出,最大交易利润为:5
a.性能分析
假定数组S的长度为n,外层循环运行n次,内层循环走n-i-1.因此算法的时间复杂度为:.也就是说暴力枚举法的算法复杂度为
3.分而治之法
将s分解成两部分。一部分是s的前半部分:s[0:n/2],另一部分是s的后半部分:s[n/2:n],分别计算前半部分和后半部分的最大交易利润,然后在两者中选出最大的一个.但是需要考虑一种跨界情况,那就是最大利润可能实现的方案是:在前半部分的某一天买入,在后半部分的某一天卖出,这种情况我们要在前半部分找到最小值,在后半部分找到最大值,只需要一个循环就可以实现
def findMaxProfit(s):
if len(s)<2:
return [0,0,0]
if len(s)==2:
if s[1]>s[0]:
return [0,1,s[1]-s[0]]
else:
return [0,0,0]
firstHalf=findMaxProfit(s[0:int(len(s)/2)])
secondHalf=findMaxProfit(s[int(len(s)/2):len(s)])
finalResult=firstHalf
if secondHalf[2]>firstHalf[2]:
# 后半部分的交易日期要加上前半部分的天数
secondHalf[0]+=int(len(s)/2)
secondHalf[1]+=int(len(s)/2)
finalResult=secondHalf
# 看最大利润方案是否是在前半部分买入,后半部分卖出
lowestPrice=s[0]
highestPrice=s[int(len(s)/2)]
buyDay=0
sellDay=int(len(s)/2)
for i in range(0,int(len(s)/2)):
if s[i]<lowestPrice:
buyDay=i
lowestPrice=s[i]
for i in range(int(len(s)/2),len(s)):
if s[i]>highestPrice:
sellDay=i
highestPrice=s[i]
if highestPrice-lowestPrice>finalResult[2]:
finalResult[0]=buyDay
finalResult[1]=sellDay
finalResult[2]=highestPrice-lowestPrice
return finalResult
s=[10,4,8,7,9,6,2,5,3]
maxprofit=findMaxProfit(s)
print(maxprofit[0]+1,maxprofit[1]+1,maxprofit[2])
2 5 5
a.分析性能
算法把一个大问题先分解成两个子问题加以解决,最后再进行一次大循环,因此算法复杂度公式为:
4.最优解法
假设最佳交易方案是第N太难卖出,那么很显然,最佳的买入时机就是前N-1天中价格最低的时候,也就是要在s[0:N]中的最小值时买入.如果把最小值记为Min(s[0:N],那么最大利润就是profit=s[N]-Min(s[0:N]).因此我们可以将N从1遍历到n,然后找出最大利润,此时只需遍历数组一次就可以完成
from IPython.display import Image
Image(filename="./data/1_1.png",width=800)
s=[10,4,8,7,9,6,2,5,3]
maxprofit=0
leftmin=s[0]
buyDay=0
sellDay=0
tmp=0
for i in range(len(s)):
if s[i]<leftmin:
leftmin=s[i]
tmp=i
if s[i]-leftmin>maxprofit:
maxprofit=s[i]-leftmin
buyDay=tmp
sellDay=i
print("应该在第{0}天买入,第{1}天卖出,最大交易利润为:{2}".format(buyDay+1,sellDay+1,maxprofit))
应该在第2天买入,第5天卖出,最大交易利润为:5
a.性能分析
这种方法只需把数组遍历一次,因此时间复杂度为O(n),它的效率最高