#ruby
#ruby
Вопрос:
Из числа я хочу сгенерировать разные группы чисел, где сумма соответствует этому числу.
Пример:
generate_groups([], 1) would be equal to [ [1] ]
generate_groups([], 2) would be equal to [ [1,1] , [2] ]
generate_groups([], 3) would be equal to [ [1, 1, 1], [1, 2], [2, 1], [3] ]
Я уже написал решение в итеративном коде, но есть лучший ответ в рекурсивном.
Итак, я написал следующий код:
def generate_groups(combo = [], rest)
return combo.flatten if rest <= 0
result = []
(1..rest).each do |number|
combo << number
tmp_res = generate_groups(combo, rest-number)
result << tmp_res
combo.pop
end
return result
end
Но это нехорошо, потому что это генерирует массив в array.
Например, generate_groups([], 3)
это:
[ [ [ [1, 1, 1] ], [1, 2] ] , [ [2, 1] ] , [3] ]
Что не так в моем алгоритме?
Комментарии:
1. не имеет отношения к вашему алгоритму, но, возможно, быстрый совет ruby: если вы измените аргументы для generate_groups на противоположные, тогда вы можете сделать, чтобы второй был необязательным (
generate_groups(rest, combo=[])
) для вызова какgenerate_groups(1) or generate_groups(1, [])
2. @TMP: Это тоже работает так, как есть (начиная с Ruby 2, IIRC).
3. @undur_gongor о, ладно, это круто, я этого не знал. Мне просто показалось странным, что вы указываете пустой массив в своем примере, хотя
Ответ №1:
Ваше решение может быть исправлено следующим образом:
def generate_groups(combo = [], rest)
return [combo.dup] if rest <= 0 # no need for flattening
result = []
(1..rest).each do |number|
combo << number
tmp_res = generate_groups(combo, rest-number)
result = tmp_res # concat the solutions instead of nesting them.
combo.pop
end
return result
end
dup
Это необходимо, потому что в противном случае фиксированный результат позже будет изменен путем изменения combo
. Ваш flatten
также создал копию массива.
Однако передача внутреннего состояния ( combo
) посредством рекурсии выглядит … странно. Это не требуется. Мое предложение
def generate_groups(rest)
return [[]] if rest <= 0
(1..rest).inject([]) do | a, number |
a generate_groups(rest - number).map { | g | g << number }
end
end
С помощью inject
я объединяю массивы промежуточных результатов.