我正在努力寻找买卖这些“股票”的最佳时机。例如,数组“f”在3买入并在15卖出= = maximum_profit。我正在努力解决这个问题,开始感到有些愚蠢。我需要遍历数组并找到最好的组合,但是一旦我过了一天,我就不能在那之前的一天卖掉它,只有在之后。
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
b = [9, 8, 7, 6, 5, 4, 3, 2, 1]
c = [3, 4, 2, 6, 7, 4, 9, 8, 5]
d = [8, 6, 9, 2, 7, 4, 1, 5 ,1]
e = [10, 11, 2, 9, 4, 3, 5, 6]
f = [17, 3, 6, 9, 15, 8, 6, 1, 10]
def stock_picker(array)
min = array.min
min_price= array.index(min)
max = array.max
max_price = array.index(max)
end
stock_picker(a)
答案 0 :(得分:4)
这是解决问题的更多Ruby方法。这里的关键是利用像combination
这样的工具为你做很多繁重的工作,然后逐步将数据转换成所需的最终结果:
def max_profit(prices)
best = prices.combination(2).map do |buy, sell|
[ buy, sell, sell - buy ]
end.max_by do |buy, sell, profit|
profit
end
if (best[2] <= 0)
{
profit: 0
}
else
{
buy: {
at: best[0],
on: prices.index(best[0])
},
sell: {
at: best[1],
on: prices.index(best[1])
},
profit: best[2]
}
end
end
stocks = [
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[9, 8, 7, 6, 5, 4, 3, 2, 1],
[3, 4, 2, 6, 7, 4, 9, 8, 5],
[8, 6, 9, 2, 7, 4, 1, 5 ,1],
[10, 11, 2, 9, 4, 3, 5, 6],
[17, 3, 6, 9, 15, 8, 6, 1, 10]
]
stocks.each do |prices|
p max_profit(prices)
end
这会给你这样的结果:
{:buy=>{:at=>1, :on=>0}, :sell=>{:at=>9, :on=>8}, :profit=>8}
{:profit=>0}
{:buy=>{:at=>2, :on=>2}, :sell=>{:at=>9, :on=>6}, :profit=>7}
{:buy=>{:at=>2, :on=>3}, :sell=>{:at=>7, :on=>4}, :profit=>5}
{:buy=>{:at=>2, :on=>2}, :sell=>{:at=>9, :on=>3}, :profit=>7}
{:buy=>{:at=>3, :on=>1}, :sell=>{:at=>15, :on=>4}, :profit=>12}
关于combination
的一个重要属性是它保留了元素的顺序,因此这会自动排除以错误顺序发生的交易。
答案 1 :(得分:2)
我的答案是找到解决问题的有效方法。
<强>代码强>
def buy_sell(prices)
n = prices.size
imax = (1..n-1).max_by { |i| prices[i] }
imin = (0..imax-1).min_by { |i| prices[i] }
return [imin, imax] if imax >= n-2
imin_next, imax_next = buy_sell(prices[imax+1..-1]).map { |i| i + imax }
prices[imin]-prices[imax] >= prices[imin_next]-prices[imax_next] ? [imin, imax] :
[imin, imax]
end
这适用于prices.size >= 2
。
示例强>
prices = [17, 3, 6, 9, 15, 8, 6, 1, 10]
buy_sell(prices)
#=> [1, 4]
这意味着可以通过在prices[1] #=> 3
日(prices
)1
的偏移量进行购买并在prices[4] #=> 15
日4
处出售,从而获得最大的利润。 },获得12
的利润。
<强>解释强>
考虑以下每日价格数组。
prices = [17, 3, 6, 9, 15]
17
是一天的价格(抵消)0
,3
是第1
天的价格,依此类推。
我们可能首先确定i > 0
最大的prices
索引prices[i]
。
n = prices.size
#=> 5
imax = (1..n-1).max_by { |i| prices[i] }
#=> 4
自imax #=> 4
以来,我们看到prices
&#39;第一天之后的最大值是最后一天,prices[imax] #=> 15
。这告诉我们,不管我们什么时候买,我们应该在最后一天卖出(很容易被矛盾证明)。因此,仍需要计算:
imin = (0..imax-1).min_by { |i| prices[i] }
#=> 1
因此,我们应该在1
日prices[1] #=> 3
购买并在4
日15
处出售,为我们带来12
的整洁利润。< / p>
当然,第一天之后的最高价格不一定是最后一天。现在假设:
prices = [17, 3, 6, 9, 15, 8, 6, 1, 10]
这是OP的例子。现在计算第一天之后的最高价格:
n = prices.size
#=> 9
imax = (1..n-1).max_by { |i| prices[i] }
#=> 4
15
,4
天仍然是最高价格,我们已经知道在4
之前,1
天的价格最低。这样我们就可以得出以下结论:我们应该在1
天购买并在4
天销售,或者我们应该在4
之后购买(并在此之后出售)。同样,这很容易通过矛盾来证明,因为随时随地销售4
会给我们最多15
的卖价,所以我们不能通过购买获得比12
更大的利润那天4
。剩下的问题是数组
prices = [8, 6, 1, 10]
其中8
是第5
天的价格,依此类推。
由于此阵列中的最大卖价最后,我们知道最佳的是在1
天7
买入(新2
的偏移prices
}}并在第8
天(偏移3
)出售,产生9
的利润。自9 < 12
以来,我们发现最高利润是我们最初计算的。
如果prices
此处[1, 10, 8, 6]
我们计算了9
的相同利润,则必须将prices
视为数组[8, 6]
。如果这里prices
为[8, 1, 10, 6]
我们会计算9
的相同利润,但后来必须考虑prices
是数组[6]
,我们可以忽略它因为它只包含单一价格。
该算法适用于递归实现。
<强>效率强>
如果要考虑m
子阵列,则时间复杂度为O(mn),与O(n 2 )相比,可以直接比较所有对[prices[i], prices[j]]
,i < j
。
我已经执行了一个基准测试,将此方法与@tadman使用的简化版本进行比较,后者列举了所有有序对。结果如下。
def cary_buy_sell(prices)
n = prices.size
imax = (1..n-1).max_by { |i| prices[i] }
imin = (0..imax-1).min_by { |i| prices[i] }
return [imin, imax] if imax >= n-2
imin_next, imax_next = cary_buy_sell(prices[imax+1..-1]).map { |i| i + imax }
prices[imin]-prices[imax] >= prices[imin_next]-prices[imax_next] ? [imin, imax] :
[imin, imax]
end
def tadman_buy_sell(prices)
prices.combination(2).max_by { |x,y| y-x }
end
require 'fruity'
m = 20
[10, 20, 100, 1000].each do |n|
puts "\nn = #{n}, m = #{m}"
prices = m.times.map { n.times.to_a.shuffle }
compare do
tadman { prices.each { |row| tadman_buy_sell(row) } }
cary { prices.each { |row| cary_buy_sell(row) } }
end
end
报告以下内容。
n = 10, m = 20
Running each test 16 times. Test will take about 1 second.
cary is faster than tadman by 1.9x ± 0.1
n = 20, m = 20
Running each test 8 times. Test will take about 1 second.
cary is faster than tadman by 4x ± 0.1
n = 100, m = 20
Running each test once. Test will take about 1 second.
cary is faster than tadman by 22x ± 1.0
n = 1000, m = 20
Running each test once. Test will take about 28 seconds.
cary is faster than tadman by 262x ± 10.0
出于好奇,我计算了每个测试n
值所需的平均递归数。结果如下。
average number of
n recursions required
---------------------------
10 2.40
20 2.55
100 4.50
1,000 6.65
10,000 8.55
50,000 9.85
100,000 11.60
500,000 13.40
当n
等于100
时,平均而言,需要一系列4.50
递归计算(即,每个都确定价格子阵列的最大值,然后确定最大值之前的最小值)。不出意外,当n
增加时,这个数字会缓慢增加。