재귀 함수로 2 ** n-1을 쓰는 방법?


49

n을 취하고 2 n -1을 반환하는 함수가 필요합니다 . 충분히 간단하게 들리지만 함수는 재귀 적이어야합니다. 지금까지 나는 단지 2 n :

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

운동 상태 : "매개 변수 n이 항상 양의 정수이고 0보다 크다고 가정 할 수 있습니다."


4
기록을 위해, 교대하고 빼는 평범한 사람처럼하는 것이 훨씬 더 효율적이어야합니다. 파이썬 정수는 임의의 너비이므로 1 << n오버플로 할 수 없습니다. 이것은 (1<<n) - 1여러 단계 로 분해하는 방법을 발명하는 연습으로 보입니다 . 아마도 대답이 보여주는 것처럼 각 비트를 한 번에 하나씩 설정하는 것입니다.
Peter Cordes

8
def fn(n): if n == 0: return 1; return (2 << n) - fn(0); # technically recursive
MooseBoys 2018 년

3
@Voo : Carl은 아니지만 포함 된 모든 내용을 알려주십시오.C:\MyFolder
Flater

1
@Voo : 재귀의 개념을 가르치는 데 초점을 둔 운동에 의존성 여부는 관계가 없습니다. 학생들이 사용할 수있는 기본 조롱 클래스 / 메서드를 만들 수있었습니다. 당신은 운동의 포인트 외에 완전히 다른 것에 집중하고 있습니다. 파일 시스템 탐색을 사용하는 것은 학생들이 일반적으로 폴더와 파일의 본질적으로 반복되는 특성을 이해 하기 때문에 좋은 예입니다 (즉, 폴더는 무기한으로 서로 중첩 될 수 있음)
Flater

1
@Voo 아니오 재귀 데이터 구조를 보여줌으로써 재귀를 가르 칠 수 있다고 말하고 있습니다. 나는 왜 당신이 이것을 이해하는데 어려움을 겪고 있는지 모른다.
Flater

답변:


54

2**n -1또한 1 + 2 + 4 + ... + 2 n-1 이며 단일 재귀 함수로 만들 수 있습니다 (두 번째는 2의 거듭 제곱에서 1을 빼지 않음).

힌트 : 1 + 2 * (1 + 2 * (...))

아래 해결책은 먼저 힌트를 시도하고 있는지 확인하지 마십시오.


이것은 n실제로 문제 설명에서 약속 한 것처럼 0보다 큰 것이 보장되는 경우 작동합니다 .

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

보다 강력한 버전은 0과 음수 값도 처리합니다.

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)

(정수가 아닌 사람에 대한 검사 추가는 연습으로 남습니다.)


4
그러나 required_steps(0)이제 무한 재귀를 일으킨다
감사합니다.

7
2^0 - 1== 0. if해당 경우에 다른 것을 추가하십시오 .
h4z3

9
@ user633183 예, 총 기능이 무엇인지 알고 있습니다. 당신 은요? 그것은 완전한 기능이 될 수 없기 때문입니다. 다른 답변도 전체 기능도 아닙니다. 그리고 그렇습니다. 전체 기능을 만들려면 더 많은 코드가 필요합니다. -내가 말했듯이, 우리는 도메인이 없습니다. 도메인이 무엇이라고 가정해야합니까? 그것이 단지조차 int, 우리는 n <0 일 때 무엇을해야할지 모른다. 계산하다? 오류를 던져? 0을 반환 하시겠습니까? 이 경우 부분 함수 만 수행 할 수 있습니다 (결과가 무엇인지 아는 것에 대해 정의하십시오).
h4z3

4
영업 이익의 코드베이스 케이스입니다 0및 사용 n - 1하위 문제에 대한. Natural Numbers 의 도메인은 잘 맞는 것 같습니다.
감사합니다.

4
정말 고맙습니다! 겸손한 견해로는 이것이 특정 문제에 대한 최상의 솔루션입니다. 나는 n에 가능한 값을 말하지 않았다. 정말로 미안하다! 연습 문제 : "매개 변수 n은 항상 양의 정수이고 0보다 크다고 가정 할 수 있습니다"
Kajice

37

재귀 접근 방식의 문제를 해결하려면 다른 입력을 사용하는 동일한 함수의 관점에서 주어진 입력으로 함수를 정의하는 방법을 찾아야합니다. 이 경우 이후부터 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

정말 재귀적인 부분을 다른 함수로 추출 할 수 있습니다

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

결과에 추가 매개 변수를 사용하여 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)

출력은 같습니다


2
간단한 곱셈 연습을 위해 비트 단위 연산이 불필요합니다. 전혀 읽을 수 없습니다. 또한, else어느 기능에서든 조항이 필요하지 않습니다
rafaelc

유일한 차이점은 변화 r * 2r << 1그는 "전혀 읽을 수 없습니다"인가? 😂
감사합니다.

2
두 번째 매개 변수를 발명하면 왼쪽으로 이동하는 루프로 전환됩니다. n 시간 한 다음 1을 빼는 . 모든 것이 비효율적 인 대 운동이지만, 덜 우아하고 필요한 것 같습니다 (1<<n) - 1.
Peter Cordes 19

1
@PeterCordes : 어큐뮬레이터 파라미터로 이동 상태 것은 꼬리 재귀 호출로 재귀 호출을 변환하는 표준 방법. 자, 불행하게도, 파이썬은 적절한 테일 전화, 심지어 적절한 꼬리 재귀를 지원하지 않습니다,하지만 이것은 당신이 다른 언어에 적용 할 수 있도록 배울 수있는 유용한 기술 아니라는 것을 의미하지 않는다 적절한 테일 통화를 구현 또는 적어도 적절한 꼬리 재귀.
Jörg W Mittag

1
@ JörgWMittag 예, 그러나이 경우 루프 보다 더 자연 스럽다는 사실을 위장하기는 어렵습니다 . 어쩌면 어셈블리 언어와 성능에 너무 많은 시간을 할애했을 수도 있지만, 꼬리 재귀를 사용하여 "루프"를 작성하는 것은 루프를 작성할 수있을 때 명령형 언어에서 의미가없는 것처럼 보입니다. 또는이 답변에 대해 나를 괴롭히는 것은 분해 방법을 선택하는 것입니다. 한 번에 하나씩 교대 한 다음 기본 사례로 최종 뺄셈입니다. 아마 둘 다의 조합 일 것입니다.
피터 코 데스

0

바로 그 첫 번째 단계 즉위한 후 원래 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)

-1

"-1"의 오프셋을 얻는 한 가지 방법은 기본값을 가진 인수를 사용하여 첫 번째 함수 호출의 리턴에이를 적용한 다음 재귀 호출 중에 오프셋 인수를 명시 적으로 0으로 설정하는 것입니다.

def required_steps(n, offset = -1):
    if n == 0:
        return 1
    return offset + 2 * required_steps(n-1,0)

-1

이전에 제공된 모든 멋진 답변 외에도 아래는 내부 함수를 사용한 구현을 보여줍니다.

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의 전역 값을 할당하고 적절한 비교를 통해 반복합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.