记住两个数字组合的有效方法

时间:2017-07-12 19:18:06

标签: ruby recursion dynamic-programming memoization

我正在研究一种算法来计算构建100美分的方法,给出无限量的硬币,硬币,零钱和四分之一。

我最终选择了以上(AFAIK的工作原理):

def count_ways(amount)
  num_ways(amount, 0)
end

def num_ways(amount, index)
  return 1 if amount == 0
  return 0 if index >= COINS.length || amount < 0
  num_ways(amount - COINS[index], index) +
  num_ways(amount, index + 1)
end

现在,我想记住这个算法。我发现考虑记忆的一种有效方法是考虑我们反复传递给这个函数的输入。在这种情况下,我想记住金额和金额的组合。索引参数。

通常当我有两个参数时,我会构建一个两个D数组作为记忆的方法,但这里的意义却大打折扣。那么,你怎么能记下这两个参数呢?做这样的事情有意义吗?

def count_ways(amount)
  memo = Hash.new { |h, k| h[k] = [] }
  num_ways(amount, 0, memo)
end

def num_ways(amount, index, memo)
  return 1 if amount == 0
  return 0 if index >= COINS.length || amount < 0
  memo[amount - COINS[index], index] ||= num_ways(amount - COINS[index], index)
  memo[amount, index + 1] ||= num_ways(amount, index + 1)

  memo[amount - COINS[index], index] +
    memo[amount, index + 1]
end

2 个答案:

答案 0 :(得分:0)

我相信在解决算法任务时没有通用的方法来实现memoization。因为速度快。您必须选择的方式取决于您的算法,输入数据等。 几个必要的规则:

  • 避免创建许多数据结构实例:h = {}; h[ [1,2] ] = 3只会为密钥生成COINS.size * amount Array
  • Array用于连续的数据,将Hash用于有缺口的一个
  • 当您无法预测数据大小时,请使用Hash代替Array
  • 当您可以预测您的身份时,使用所需的值创建Array 连续数据大小

使用该规则,memoization(仅在您的情况下,COINS.size&lt;&lt; amount并且两个数据连续)可能如下所示:

COINS = [25, 10, 5, 1]

def count_ways(amount)
  # memo is just COINS.size + 1 Array instances
  # a[0] = 1 instead of return 1 if amount == 0
  memo = Array.new(COINS.size){ Array.new(amount).tap{ |a| a[0] = 1 } }
  num_ways(amount, 0, memo)
end

def num_ways(amount, index, memo)
  return 0 if index >= COINS.size || amount < 0

  memo[index][amount] ||=
    num_ways(amount - COINS[index], index, memo) +
    num_ways(amount, index + 1, memo)
end

P.S。 dynamic-programming标记是不必要的:)

答案 1 :(得分:-1)

由于相同的数组具有不同的对象ID,因此您无法将值作为数组放入散列键中。但是你可以转换为字符串来制作一个简单的查找结构,例如转换为YAML / JSON

require 'json'

memo = {}
def memoize(*args, &blk)
  memo[args.to_json] ||= blk.call
end
def num_ways(amount, index)
  memoize(amount, index) do
    # original method body
  end
end

修改

没关系,我想我需要使用to_json。您可以在args内使用memoize而不是args.to_json