Вот мое решение в Ruby
def combination(length=5)
return [[]] if length == 0
combination(length-1).collect {|c| [:h] + c if c[0..1]!= [:h,:h]}.compact +
combination(length-1).collect {|c| [:t] + c }
end
puts "There are #{combination.length} ways"
Все рекурсивные методы начинаются с раннего завершения для конечного случая.
return [[]] if length == 0
Возвращает массив комбинаций, где единственной комбинацией нулевой длины является []
Следующий бит (упрощенный): ...
combination(length-1).collect {|c| [:h] + c } +
combination(length-1).collect {|c| [:t] + c }
Итак ... это говорит ... Я хочу, чтобы все комбинации были на одну короче желаемой длины с добавленной к каждой из них головой: ... плюс все комбинации, которые на одну короче с добавленным к ним хвостом.
Способ думать о рекурсии заключается в том, что ... «предполагая, что у меня есть метод для случая n-1 ... что я должен был бы добавить, чтобы он покрыл случай n» ». Для меня это похоже на доказательство по индукции.
Этот код будет генерировать все комбинации голов и хвостов до заданной длины.
Нам не нужны те, которые имеют: h: h: h. Это может произойти только тогда, когда у нас есть: h: h и мы добавляем a: h. Итак ... Я добавил if c[0..1] != [:h,:h]
при добавлении: h, чтобы он возвращал nil
вместо массива, когда собирался создать недопустимую комбинацию.
Затем мне пришлось compact
результат, чтобы игнорировать все результаты, которые просто nil