需要帮助操作ruby中的数组

时间:2017-07-23 03:00:36

标签: ruby

我正在努力寻找买卖这些“股票”的最佳时机。例如,数组“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)

2 个答案:

答案 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日(prices1的偏移量进行购买并在prices[4] #=> 154处出售,从而获得最大的利润。 },获得12的利润。

<强>解释

考虑以下每日价格数组。

prices = [17, 3, 6, 9, 15]

17是一天的价格(抵消)03是第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

因此,我们应该在1prices[1] #=> 3购买并在415处出售,为我们带来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

154天仍然是最高价格,我们已经知道在4之前,1天的价格最低。这样我们就可以得出以下结论:我们应该在1天购买并在4天销售,或者我们应该在4之后购买(并在此之后出售)。同样,这很容易通过矛盾来证明,因为随时随地销售4会给我们最多15的卖价,所以我们不能通过购买获得比12更大的利润那天4。剩下的问题是数组

 prices = [8, 6, 1, 10]

其中8是第5天的价格,依此类推。

由于此阵列中的最大卖价最后,我们知道最佳的是在17买入(新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增加时,这个数字会缓慢增加。