동적 프로그래밍이란 무엇입니까? [닫은]


276

동적 프로그래밍 이란 무엇입니까 ?

재귀, 메모 등은 어떻게 다릅니 까?

위키피디아 기사 를 읽었 지만 여전히 이해하지 못합니다.


1
저는 여기에 특히 도움이 발견 CMU에서 마이클 A. 트릭 하나 튜토리얼은 다음과 같습니다 mat.gsia.cmu.edu/classes/dynamic/dynamic.html 그것은 특별히 다른 사람이 추천 한 모든 자원 (다른 모든 자원에 추가 확실히 CLR 그리고 Kleinberg, Tardos는 매우 좋습니다!). 이 튜토리얼을 좋아하는 이유는 고급 개념을 상당히 점진적으로 소개하기 때문입니다. 약간 오래된 자료이지만 여기에 제시된 자료 목록에 추가하기에 좋습니다. 또한 동적 프로그래밍에 대한 Steven Skiena의 페이지와 강의를 확인하십시오 : cs.sunysb.edu/~algorith/video-lectures http :
Edmon

11
나는 항상 "동적 프로그래밍"이라는 혼란스러운 용어를 발견했습니다. "동적"은 정적이 아니라고 제안하지만 "정적 프로그래밍"은 무엇입니까? 그리고 "... Programming"은 "Object Oriented Programming"과 "Functional Programming"을 염두에두고 DP가 프로그래밍 패러다임을 제안합니다. 나는 더 나은 이름을 가지고 있지는 않지만 (아마 "Dynamic Algorithms"?) 우리가이 이름을 고수하는 것은 너무 나쁘다.
dimo414

3
@ dimo414 여기서 "프로그래밍"은 수학 최적화 방법에 속하는 "선형 프로그래밍"과 관련이 있습니다. 다른 수학적 프로그래밍 방법 목록은 수학적 최적화 기사를 참조하십시오 .
syockit

1
@ dimo414이 문맥에서 "프로그래밍"은 컴퓨터 코드를 작성하는 것이 아니라 테이블 형식의 방법을 나타냅니다. -Coreman
user2618142

cs.stackexchange.com/questions/59797/…에 설명 된 버스 티켓 비용 최소화 문제는 동적 프로그래밍에서 가장 잘 해결됩니다.
truthadjustr

답변:


210

동적 프로그래밍은 과거 지식을 사용하여 미래의 문제를보다 쉽게 ​​해결하는 것입니다.

좋은 예는 n = 1,000,002의 피보나치 수열을 푸는 것입니다.

이 과정은 매우 오래 걸리지 만 n = 1,000,000 및 n = 1,000,001에 대한 결과를 제공하면 어떻게됩니까? 갑자기 문제가 더 관리하기 쉬워졌습니다.

동적 프로그래밍은 문자열 편집 문제와 같은 문자열 문제에서 많이 사용됩니다. 문제의 하위 집합을 해결 한 다음 해당 정보를 사용하여보다 어려운 원래 문제를 해결합니다.

동적 프로그래밍을 사용하면 일반적으로 결과를 일종의 테이블에 저장합니다. 문제에 대한 답이 필요할 때 표를 참조하여 이미 무엇인지 알고 있는지 확인하십시오. 그렇지 않은 경우 테이블의 데이터를 사용하여 답을 향한 디딤돌이됩니다.

Cormen Algorithms 책에는 동적 프로그래밍에 대한 훌륭한 장이 있습니다. 그리고 그것은 Google 도서에서 무료입니다! 여기서 확인 하십시오.


50
그래도 메모를 설명하지 않았습니까?
dreadwail

31
메모리 화 된 함수 / 메소드가 재귀적일 때, 메모리 화는 다이내믹 프로그래밍의 한 형태라고 말할 수 있습니다.
Daniel Huckstep

6
좋은 대답은 최적의 하위 구조에 대한 언급 만 추가하는 것입니다 (예 : A에서 B까지의 최단 경로를 따르는 경로의 모든 하위 세트 자체는 삼각형 불평등을 관찰하는 거리 메트릭을 가정 할 때 두 끝점 사이의 최단 경로 임).
Shea

5
"더 쉬워"라고 말하지는 않지만 더 빠릅니다. 일반적인 오해는 dp가 순진한 알고리즘으로는 할 수없는 문제를 해결한다는 것입니다. 기능의 문제가 아니라 성능의 문제입니다.
andandandand

6
메모를 사용하면 동적 프로그래밍 문제를 하향식으로 해결할 수 있습니다. 즉, 최종 값을 계산하기 위해 함수를 호출하면 해당 함수는 하위 문제를 해결하기 위해 자체 재귀 적으로 호출합니다. 그것 없이는 동적 프로그래밍 문제는 상향식으로 만 해결할 수 있습니다.
Pranav

175

동적 프로그래밍은 재귀 알고리즘에서 동일한 하위 문제를 여러 번 계산하지 않도록하는 기술입니다.

하자가 피보나치 수의 간단한 예제를 가지고 : n 개의 찾는 에 의해 정의 된 피보나치 수를

F n = F n-1 + F n-2 및 F 0 = 0, F 1 = 1

재귀

이를 수행하는 확실한 방법은 재귀 적입니다.

def fibonacci(n):
    if n == 0:
        return 0
    if n == 1:
        return 1

    return fibonacci(n - 1) + fibonacci(n - 2)

다이나믹 프로그래밍

  • 하향식-메모

주어진 피보나치 수는 여러 번 계산되므로 재귀는 불필요한 계산을 많이 수행합니다. 이를 개선하는 쉬운 방법은 결과를 캐시하는 것입니다.

cache = {}

def fibonacci(n):
    if n == 0:
        return 0
    if n == 1:
        return 1
    if n in cache:
        return cache[n]

    cache[n] = fibonacci(n - 1) + fibonacci(n - 2)

    return cache[n]
  • 상향식

이를 수행하는 더 좋은 방법은 결과를 올바른 순서로 평가하여 재귀를 완전히 제거하는 것입니다.

cache = {}

def fibonacci(n):
    cache[0] = 0
    cache[1] = 1

    for i in range(2, n + 1):
        cache[i] = cache[i - 1] +  cache[i - 2]

    return cache[n]

일정한 공간을 사용하고 필요한 부분 결과 만 저장할 수 있습니다.

def fibonacci(n):
  fi_minus_2 = 0
  fi_minus_1 = 1

  for i in range(2, n + 1):
      fi = fi_minus_1 + fi_minus_2
      fi_minus_1, fi_minus_2 = fi, fi_minus_1

  return fi
  • 동적 프로그래밍을 어떻게 적용합니까?

    1. 문제의 재귀를 찾으십시오.
    2. 하향식 : 각 하위 문제에 대한 답을 표에 저장하여 다시 계산하지 않아도됩니다.
    3. 상향식 : 필요한 경우 부분 결과를 사용할 수 있도록 결과를 평가하기위한 올바른 순서를 찾으십시오.

동적 프로그래밍은 일반적으로 문자열, 트리 또는 정수 시퀀스와 같이 고유 한 왼쪽에서 오른쪽 순서로 문제가있는 경우 작동합니다. 순진 재귀 알고리즘이 동일한 하위 문제를 여러 번 계산하지 않으면 동적 프로그래밍이 도움이되지 않습니다.

나는 논리를 이해하는 데 도움이되는 문제 모음을 만들었습니다 : https://github.com/tristanguigue/dynamic-programing


3
이것은 훌륭한 답변이며 Github의 문제 모음도 매우 유용합니다. 감사!
p4sh4

당신의 의견으로는 되풀이 관계와 메모를 사용하는 재귀 구현은 동적 프로그래밍입니까?
Codor

설명 주셔서 감사합니다. if n in cache하향식 예에서와 같이 상향식에서 누락 된 조건이 있습니까? 아니면 뭔가 빠졌습니다.
DavidC

각 반복에서 계산 된 값이 후속 반복에서 사용되는 루프가 동적 프로그래밍의 예라는 것을 올바르게 이해하고 있습니까?
Alexey

하향식 및 상향식 특수 사례를 포함하여 해석에 대한 언급을 할 수 있습니까?
Alexey

37

Memoization은 함수 호출의 이전 결과를 저장할 때입니다 (실제 함수는 동일한 입력이 주어지면 항상 같은 것을 반환합니다). 결과가 저장되기 전에 알고리즘 복잡성에 차이가 없습니다.

재귀는 일반적으로 더 작은 데이터 집합으로 함수를 호출하는 메서드입니다. 대부분의 재귀 함수는 유사한 반복 함수로 변환 될 수 있기 때문에 알고리즘 복잡성에도 차이가 없습니다.

동적 프로그래밍은 해결하기 쉬운 하위 문제를 해결하고 그로부터 해답을 얻는 과정입니다. 대부분의 DP 알고리즘은 Greedy 알고리즘 (있는 경우)과 지수 (모든 가능성을 열거하고 최상의 알고리즘을 찾습니다) 사이의 실행 시간에 있습니다.

  • DP 알고리즘은 재귀로 구현 될 수 있지만 반드시 그럴 필요는 없습니다.
  • DP 알고리즘은 각 하위 문제가 한 번만 해결되기 때문에 메모 화로 속도를 낼 수 없습니다.

매우 명확하게 말하십시오. 알고리즘 강사가 이것을 잘 설명하기를 바랍니다.
Kelly S. French

21

실행 시간을 줄이는 알고리즘 최적화입니다.

Greedy Algorithm은 일반적으로 동일한 데이터 세트에서 여러 번 실행될 수 있기 때문에 일반적으로 naive 라고하지만 Dynamic Programming은 최종 솔루션을 빌드하기 위해 저장해야하는 부분 결과에 대한 심층적 인 이해를 통해 이러한 함정을 피합니다.

간단한 예는 솔루션에 기여하는 노드를 통해서만 트리 또는 그래프를 순회하거나, 지금까지 찾은 솔루션을 테이블에 배치하여 동일한 노드를 순회하는 것을 피할 수 있습니다.

다음은 UVA의 온라인 판사 인 Edit Steps Ladder 의 동적 프로그래밍에 적합한 문제의 예입니다 .

Programming Challenges 책에서 발췌 한이 문제 분석의 중요한 부분을 간략히 설명하겠습니다. 확인해보십시오.

두 문자열이 얼마나 멀리 있는지 알려주는 비용 함수를 정의하면 그 문제를 잘 살펴보십시오.

대체- "shot"을 "spot"으로 변경하는 것과 같이 단일 문자를 패턴 "s"에서 텍스트 "t"의 다른 문자로 변경하십시오.

삽입- "ago"를 "agog"로 변경하는 것과 같이 텍스트 "t"와 일치하도록 패턴 "s"에 단일 문자를 삽입합니다.

삭제-패턴 "s"에서 단일 문자를 삭제하여 "hour"를 "our"로 변경하는 것과 같이 텍스트 "t"와 일치하도록하십시오.

이 각 작업을 한 단계 비용으로 설정하면 두 문자열 사이의 편집 거리를 정의합니다. 어떻게 계산합니까?

문자열의 마지막 문자가 일치, 대체, 삽입 또는 삭제되어야한다는 관찰을 사용하여 재귀 알고리즘을 정의 할 수 있습니다. 마지막 편집 작업에서 문자를 잘라 내면 한 쌍의 작업에서 한 쌍의 작은 문자열이 남습니다. i와 j를 각각 관련 접두사와 t의 마지막 문자라고합시다. 일치 / 대체, 삽입 또는 삭제 후 문자열에 해당하는 마지막 조작 후 3 개의 더 짧은 문자열 쌍이 있습니다. 세 쌍의 더 작은 문자열을 편집하는 비용을 알고 있다면 어떤 솔루션이 가장 적합한 솔루션인지 결정하고 그에 따라 해당 옵션을 선택할 수 있습니다. 우리는 재귀의 놀라운 것을 통해이 비용을 배울 수 있습니다.

#define MATCH 0 /* enumerated type symbol for match */
#define INSERT 1 /* enumerated type symbol for insert */
#define DELETE 2 /* enumerated type symbol for delete */


int string_compare(char *s, char *t, int i, int j)

{

    int k; /* counter */
    int opt[3]; /* cost of the three options */
    int lowest_cost; /* lowest cost */
    if (i == 0) return(j * indel(’ ’));
    if (j == 0) return(i * indel(’ ’));
    opt[MATCH] = string_compare(s,t,i-1,j-1) +
      match(s[i],t[j]);
    opt[INSERT] = string_compare(s,t,i,j-1) +
      indel(t[j]);
    opt[DELETE] = string_compare(s,t,i-1,j) +
      indel(s[i]);
    lowest_cost = opt[MATCH];
    for (k=INSERT; k<=DELETE; k++)
    if (opt[k] < lowest_cost) lowest_cost = opt[k];
    return( lowest_cost );

}

이 알고리즘은 정확하지만 속도가 느립니다.

우리 컴퓨터에서 실행하면 두 개의 11 문자 문자열을 비교하는 데 몇 초가 걸리며 계산은 더 이상 더 이상 이루어지지 않습니다.

알고리즘이 왜 그렇게 느린가요? 값을 반복해서 다시 계산하기 때문에 지수 시간이 걸립니다. 문자열의 모든 위치에서 재귀는 3 가지 방식으로 분기되는데, 이는 적어도 3 ^ n의 속도로 증가한다는 것을 의미합니다. 실제로 대부분의 통화는 두 지수 중 하나만 감소시키기 때문에 두 지수 중 하나만 감소하기 때문에 훨씬 빠릅니다.

그렇다면 어떻게 알고리즘을 실용적으로 만들 수 있을까요? 중요한 재귀 호출은 대부분 이전에 이미 계산 된 컴퓨팅 작업이라는 것입니다. 우리가 어떻게 알아? 글쎄, | s | 만있을 수 있습니다 · | t | 재귀 호출의 매개 변수로 사용할 고유 한 (i, j) 쌍이 많기 때문에 가능한 고유 재귀 호출입니다.

이들 (i, j) 쌍 각각에 대한 값을 테이블에 저장함으로써, 재 계산을 피하고 필요에 따라 찾아 볼 수 있습니다.

표는 2 차원 행렬 m이며, 여기서 각각의 | s | · | t | 셀에는이 하위 문제에 대한 최적의 솔루션 비용과이 위치에 도달 한 방법을 설명하는 부모 포인터가 포함됩니다.

typedef struct {
int cost; /* cost of reaching this cell */
int parent; /* parent cell */
} cell;

cell m[MAXLEN+1][MAXLEN+1]; /* dynamic programming table */

동적 프로그래밍 버전은 재귀 버전과 세 가지 차이점이 있습니다.

먼저 재귀 호출 대신 테이블 조회를 사용하여 중간 값을 가져옵니다.

** 두 번째 **는 각 셀의 부모 필드를 업데이트하므로 나중에 편집 순서를 재구성 할 수 있습니다.

** 세 번째, ** 세 번째는 cell()m [| s |] [| t |] .cost를 반환하는 대신 보다 일반적인 목표 함수를 사용하여 계측됩니다 . 이를 통해 우리는이 루틴을 광범위한 문제에 적용 할 수 있습니다.

여기에서 가장 최적의 부분 결과를 수집하는 데 필요한 매우 구체적인 분석은 솔루션을 "동적"으로 만드는 것입니다.

다음 은 동일한 문제에 대한 대체 솔루션입니다. 실행이 다르더라도 "동적"입니다. 솔루션을 UVA 온라인 판사에게 제출하여 솔루션의 효율성을 확인하십시오. 나는 그러한 무거운 문제가 어떻게 그렇게 효율적으로 해결되었는지 놀랍습니다.


스토리지가 실제로 동적 프로그래밍이어야합니까? 건너 뛰는 작업량이 알고리즘을 동적으로 규정하지 않습니까?
Nthalk

당신은 최적의 수집 단계에 의해 단계 알고리즘 "동적"를 만드는 결과를. 동적 프로그래밍은 OR에서의 Bellman의 작업에서 비롯됩니다. "어떤 양의 단어라도 건너 뛰는 것이 동적 프로그래밍"이라고 말하면 검색 휴리스틱이 동적 프로그래밍이므로 용어를 평가하지 않습니다. en.wikipedia.org/wiki/Dynamic_programming
andandand

12

동적 프로그래밍의 핵심 부분은 "중복 하위 문제"및 "최적 하위 구조"입니다. 문제의 이러한 특성은 최적의 솔루션이 하위 문제에 대한 최적의 솔루션으로 구성됨을 의미합니다. 예를 들어 최단 경로 문제는 최적의 하위 구조를 나타냅니다. A에서 C까지의 최단 경로는 A에서 일부 노드 B까지의 최단 경로에 이어 해당 노드 B에서 C까지의 최단 경로입니다.

가장 짧은 경로 문제를 해결하려면 다음을 수행하십시오.

  • 시작 노드에서 노드에 닿는 모든 노드까지의 거리를 찾습니다 (예 : A에서 B 및 C로).
  • 해당 노드와 노드 사이의 거리를 찾습니다 (B에서 D 및 E로, C에서 E 및 F로)
  • 우리는 이제 A에서 E까지의 최단 경로를 알고 있습니다. 우리가 방문한 일부 노드 x에 대한 Ax와 xE의 최단 합입니다 (B 또는 C).
  • 최종 목적지 노드에 도달 할 때까지이 과정을 반복하십시오

우리는 상향식으로 작업하고 있기 때문에 하위 문제를 해결하는 데 도움이 될 때까지 하위 문제에 대한 해결책을 이미 가지고 있습니다.

동적 프로그래밍 문제에는 하위 문제가 겹치거나 최적의 하위 구조가 있어야합니다. 피보나치 시퀀스 생성은 동적 프로그래밍 문제가 아닙니다. 하위 문제가 겹치기 때문에 메모를 사용하지만 최적화 문제가 없기 때문에 최적의 하위 구조가 없습니다.


1
IMHO, 이것은 동적 프로그래밍의 관점에서 의미있는 유일한 대답입니다. 사람들이 피보나치 수를 사용하여 DP를 설명하기 시작한 이래로 궁금합니다.
Terry Li

@TerryLi, "센스"를 만들고 있을지 모르지만 이해하기 쉽지 않습니다. 피보나치 수 문제는 알려져 있고 이해하기 쉽다.
Ajay

5

다이나믹 프로그래밍

정의

동적 프로그래밍 (DP)은 하위 문제가 겹치는 문제를 해결하기위한 일반적인 알고리즘 설계 기술입니다. 이 기술은 1950 년대 미국의 수학자 "Richard Bellman"에 의해 발명되었습니다.

핵심 아이디어

핵심 아이디어는 재 계산을 피하기 위해 작은 하위 문제가 겹치는 것에 대한 답변을 저장하는 것입니다.

동적 프로그래밍 속성

  • 더 작은 인스턴스에 대한 솔루션을 사용하여 인스턴스를 해결합니다.
  • 작은 인스턴스에 대한 솔루션은 여러 번 필요할 수 있으므로 결과를 테이블에 저장하십시오.
  • 따라서 각 작은 인스턴스는 한 번만 해결됩니다.
  • 시간을 절약하기 위해 추가 공간이 사용됩니다.

4

또한 동적 프로그래밍 (특정 유형의 문제에 대한 강력한 알고리즘)을 처음 접했습니다.

가장 간단한 말로, 동적 프로그래밍을 이전 지식 을 사용하여 재귀 적 접근으로 생각하십시오.

이전 지식 이 가장 중요합니다. 이미 가지고있는 하위 문제의 해결 방법을 추적하십시오.

Wikipedia의 dp에 대한 가장 기본적인 예를 고려하십시오.

피보나치 수열 찾기

function fib(n)   // naive implementation
    if n <=1 return n
    return fib(n − 1) + fib(n − 2)

n = 5로 함수 호출을 분류하자

fib(5)
fib(4) + fib(3)
(fib(3) + fib(2)) + (fib(2) + fib(1))
((fib(2) + fib(1)) + (fib(1) + fib(0))) + ((fib(1) + fib(0)) + fib(1))
(((fib(1) + fib(0)) + fib(1)) + (fib(1) + fib(0))) + ((fib(1) + fib(0)) + fib(1))

특히 fib (2)는 처음부터 세 번 계산되었습니다. 더 큰 예에서, 더 많은 fib 값 또는 하위 문제가 재 계산되어 지수 시간 알고리즘으로 이어집니다.

이제 데이터 구조에서 이미 찾은 값을 Map 이라고 저장하여 사용해보십시오.

var m := map(0 → 0, 1 → 1)
function fib(n)
    if key n is not in map m 
        m[n] := fib(n − 1) + fib(n − 2)
    return m[n]

하위 문제의 솔루션을 아직지도에 저장하지 않은 경우지도에 저장합니다. 우리가 이미 계산 한 값을 저장하는이 기술을 메모라고합니다.

마지막으로 문제의 경우 먼저 상태를 찾아보십시오 (가능한 하위 문제 및 이전 하위 문제의 솔루션을 다른 하위 문제에 사용할 수 있도록 더 나은 재귀 접근 방식을 생각해보십시오).


Wikipedia에서 바로 리핑. 공감 !!
solidak

3

동적 프로그래밍은 하위 문제가 겹치는 문제를 해결하는 기술입니다. 동적 프로그래밍 알고리즘은 모든 하위 문제를 한 번만 해결 한 다음 답변을 테이블 (어레이)에 저장합니다. 하위 문제가 발생할 때마다 답변을 다시 계산하는 작업을 피하십시오. 동적 프로그래밍의 기본 개념은 다음과 같습니다. 일반적으로 하위 문제의 알려진 결과 테이블을 유지하여 동일한 항목을 두 번 계산하지 마십시오.

동적 프로그래밍 알고리즘 개발의 7 단계는 다음과 같습니다.

  1. 문제의 인스턴스에 솔루션을 제공하는 재귀 속성을 설정하십시오.
  2. 재귀 속성에 따라 재귀 알고리즘 개발
  3. 재귀 호출에서 문제의 동일한 인스턴스가 다시 해결되는지 확인하십시오.
  4. 메모 된 재귀 알고리즘 개발
  5. 메모리에 데이터를 저장하는 패턴을 참조하십시오
  6. 메모 된 재귀 알고리즘을 반복 알고리즘으로 변환
  7. 필요에 따라 스토리지를 사용하여 반복 알고리즘 최적화 (스토리지 최적화)

6. Convert the memoized recursive algorithm into iterative algorithm필수 단계는? 이것은 최종 형태가 비 재귀 적이라는 것을 의미합니까?
truthadjustr

필수 사항이 아닌 선택 사항
Adnan Qureshi

반복 솔루션이 모든 재귀 호출에 대해 함수 스택의 작성을 저장하므로 메모리에 데이터를 저장하는 데 사용되는 재귀 알고리즘을 저장된 값에 대한 반복으로 대체하는 것이 목적입니다.
David C. Rankin

1

요컨대 재귀 메모와 동적 프로그래밍의 차이점

이름에서 알 수 있듯이 동적 프로그래밍은 이전에 계산 된 값을 사용하여 다음 새 솔루션을 동적으로 구성합니다.

동적 프로그래밍 적용 위치 : 솔루션이 최적의 하위 구조와 겹치는 하위 문제를 기반으로하는 경우 이전 계산 된 값을 사용하면 유용하므로 다시 계산할 필요가 없습니다. 상향식 접근입니다. 이 경우 fib (n)을 계산해야한다고 가정하면 이전에 계산 된 fib (n-1) 및 fib (n-2) 값을 추가하기 만하면됩니다.

재귀 : 기본적으로 문제를 더 작은 부분으로 세분하여 쉽게 해결할 수 있지만 이전에 다른 재귀 호출에서 동일한 값을 계산 한 경우 재 계산을 피할 수는 없습니다.

메모 : 기본적으로 이전 계산 된 재귀 값을 테이블에 저장하는 것을 메모라고합니다. 이는 일부 이전 호출로 이미 계산 된 경우 재 계산을 피하므로 모든 값이 한 번 계산됩니다. 따라서 계산하기 전에이 값이 이미 계산되었는지 확인하고 이미 계산 된 경우 다시 계산하는 대신 테이블에서 동일한 값을 반환합니다. 또한 하향식 접근 방식입니다


-2

다음의 간단한 파이썬 코드 예는 Recursive, Top-down, Bottom-up피보나치 시리즈에 대한 접근 방식 :

재귀 : O (2 n )

def fib_recursive(n):
    if n == 1 or n == 2:
        return 1
    else:
        return fib_recursive(n-1) + fib_recursive(n-2)


print(fib_recursive(40))

하향식 : O (n) 더 큰 입력에 효율적

def fib_memoize_or_top_down(n, mem):
    if mem[n] is not 0:
        return mem[n]
    else:
        mem[n] = fib_memoize_or_top_down(n-1, mem) + fib_memoize_or_top_down(n-2, mem)
        return mem[n]


n = 40
mem = [0] * (n+1)
mem[1] = 1
mem[2] = 1
print(fib_memoize_or_top_down(n, mem))

상향식 : O (n) 단순하고 작은 입력 크기

def fib_bottom_up(n):
    mem = [0] * (n+1)
    mem[1] = 1
    mem[2] = 1
    if n == 1 or n == 2:
        return 1

    for i in range(3, n+1):
        mem[i] = mem[i-1] + mem[i-2]

    return mem[n]


print(fib_bottom_up(40))

첫 번째 경우에는 n ^ 2의 실행 시간이 없으며 시간 복잡도는 O (2 ^ n)입니다. stackoverflow.com/questions/360748/…
Sam

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