Как написать 2 ** n - 1 как рекурсивную функцию? - PullRequest
49 голосов
/ 14 октября 2019

Мне нужна функция, которая принимает n и возвращает 2 n - 1 . Это звучит достаточно просто, но функция должна быть рекурсивной. Пока у меня есть только 2 n :

def required_steps(n):
    if n == 0:
        return 1
    return 2 * req_steps(n-1)

В упражнении говорится: «Можно предположить, что параметр n всегда является положительным целым числом и больше 0»

Ответы [ 7 ]

54 голосов
/ 14 октября 2019

2**n -1 также 1 + 2 + 4 + ... + 2 n-1 , которые могут быть преобразованы в одну рекурсивную функцию (без второго вычитать 1от степени 2).

Подсказка : 1 + 2 * (1 + 2 * (...))

Решение ниже, не смотрите, еслиВы хотите сначала попробовать подсказку.


Это работает, если n гарантированно больше нуля (как было фактически обещано в постановке задачи):

def required_steps(n):
    if n == 1: # changed because we need one less going down
        return 1
    return 1 + 2 * required_steps(n-1)

Более надежная версия будет обрабатывать также нулевые и отрицательные значения:

def required_steps(n):
    if n < 0:
        raise ValueError("n must be non-negative")
    if n == 0:
        return 0
    return 1 + 2 * required_steps(n-1)

(Добавление проверки на нецелые числа оставлено в качестве упражнения.)

36 голосов
/ 14 октября 2019

Чтобы решить проблему с рекурсивным подходом, вам нужно выяснить, как вы можете определить функцию с заданным входом в терминах той же функции с другим входом. В этом случае, начиная с f(n) = 2 * f(n - 1) + 1, вы можете сделать:

def required_steps(n):
    return n and 2 * required_steps(n - 1) + 1

, чтобы:

for i in range(5):
    print(required_steps(i))

выводил:

0
1
3
7
15
9 голосов
/ 14 октября 2019

Вы можете извлечь действительно рекурсивную часть в другую функцию

def f(n):
    return required_steps(n) - 1

Или вы можете установить флаг и определить, когда именно вычитать

def required_steps(n, sub=True):
    if n == 0: return 1
    return 2 * required_steps(n-1, False) - sub

>>> print(required_steps(10))
1023
0 голосов
/ 15 октября 2019

Вдобавок ко всем удивительным ответам, данным ранее, ниже будет показана его реализация с внутренними функциями.

def outer(n):
    k=n
    def p(n):
        if n==1:
            return 2
        if n==k:
            return 2*p(n-1)-1
        return 2*p(n-1)
    return p(n)

n=5
print(outer(n))

По сути, это присвоение глобального значения n для k и повторение через него с соответствующими сравнениями. .

0 голосов
/ 15 октября 2019

Один из способов получить смещение «-1» - применить его в возврате из первого вызова функции, используя аргумент со значением по умолчанию, а затем явно установить аргумент смещения в ноль во время рекурсивных вызовов.

def required_steps(n, offset = -1):
    if n == 0:
        return 1
    return offset + 2 * required_steps(n-1,0)
0 голосов
/ 14 октября 2019

Используя дополнительный параметр для результата, r -

def required_steps (n = 0, r = 1):
  if n == 0:
    return r - 1
  else:
    return required_steps(n - 1, r * 2)

for x in range(6):
  print(f"f({x}) = {required_steps(x)}")

# f(0) = 0
# f(1) = 1
# f(2) = 3
# f(3) = 7
# f(4) = 15
# f(5) = 31

Вы также можете записать его, используя битовое смещение влево, << -

def required_steps (n = 0, r = 1):
  if n == 0:
    return r - 1
  else:
    return required_steps(n - 1, r << 1)

Выводто же самое

0 голосов
/ 14 октября 2019

Иметь заполнитель для запоминания исходного значения n, а затем для самого первого шага, т. Е. n == N, возврат 2^n-1

n = 10
# constant to hold initial value of n
N = n
def required_steps(n, N):
    if n == 0:
        return 1
    elif n == N:
        return 2 * required_steps(n-1, N) - 1
    return 2 * required_steps(n-1, N)

required_steps(n, N)
...