블로그를 이전하였습니다. 2023년 11월부터 https://bluemiv.github.io/에서 블로그를 운영하려고 합니다. 앞으로 해당 블로그의 댓글은 읽지 못할 수 도 있으니 양해바랍니다.
반응형
피보나치 알고리즘
피보나치(Fibonacci
) 수열은 첫번째와 두번째 원소가 0 과 1이고, 세번째 원소부터는 이전 원소 두 개의 합인 수열을 말한다.
예를들어,
0, 1, 1, 2, 3, 5, 8, 13, 21, ...
Python3 코드
아래 코드는 unittest 기반으로 작성했다. 전체 로직은 fibo()
메소드를 참고한다.
# -*- coding: utf-8 -*-
import unittest
class Exam06(unittest.TestCase):
@classmethod
def setUp(cls):
pass
def fibo(self, k):
if k == 1:
return 0
elif k == 2:
return 1
return self.fibo(k-1) + self.fibo(k-2)
def test_fibonacci(self):
self.assertEqual(0, self.fibo(1))
self.assertEqual(1, self.fibo(2))
self.assertEqual(1, self.fibo(3))
self.assertEqual(2, self.fibo(4))
self.assertEqual(3, self.fibo(5))
self.assertEqual(5, self.fibo(6))
self.assertEqual(8, self.fibo(7))
if __name__ == "__main__":
unittest.main()
k 가 1일때는 0, 2일 때는 1로 미리 정의한다. 그 이후부터는 재귀함수를 이용하여 결과값을 반환한다.
메모이제이션
위 코드에서 n 값을 작게 했을때는 문제가 없지만, 숫자가 커질수록 연산 속도가 급격히 낮아진다.
예시로 35번째 원소를 구해보자.
import time
def fibo(k):
....
start = time.time()
fibo(35)
end = time.time()
print("수행 시간: {}".format(end - start))
수행 시간: 2.8540451526641846
고작 35번째 값을 구하는데 2.85초
나 걸렸다. (해보면 알겠지만 100번째 원소를 구하려고 하면 끝나지도 않는다. 한번 해보고 얼마나 걸리는지 알려주세요)
이때, 메모이제이션을 이용한다.
메모이제이션(Memoization
)은 이미 연산한 값은 저장공간에 저장하여, 두번 이상 연산하는 일이 없도록 해준다.
Python3 코드
마찬가지로 unittest 기반으로 작성했다. 전체 로직은 fibo_memo()
메소드를 참고한다.
# -*- coding: utf-8 -*-
import unittest
class Exam06(unittest.TestCase):
...
def fibo_memo(self, memo, k):
# 이미 계산한 적이 있는 값
if memo[k] != -1:
return memo[k]
# 처음 계산하는 값
if k == 1:
memo[k] = 0
elif k == 2:
memo[k] = 1
else:
memo[k] = self.fibo_memo(memo, k-1) + self.fibo_memo(memo, k-2)
return memo[k]
def test_with_memoization(self):
memo = [-1, -1, ]
self.assertEqual(0, self.fibo_memo(memo, 1))
memo = [-1, -1, -1, ]
self.assertEqual(1, self.fibo_memo(memo, 2))
n = 35
memo = [-1 for _ in range(n + 1)]
self.assertEqual(5702887, self.fibo_memo(memo, n))
n = 50
memo = [-1 for _ in range(n + 1)]
self.assertEqual(7778742049, self.fibo_memo(memo, n))
n = 100
memo = [-1 for _ in range(n + 1)]
self.assertEqual(218922995834555169026, self.fibo_memo(memo, n))
if __name__ == "__main__":
unittest.main()
n 값을 35, 50, 100 처럼 큰 수를 넣어서 계산을 해도 바로 연산되어 값을 반환한다.
결론
피보나치 수열을 작성할때는 반드시 메모이제이션을 사용하자. n 이 조금만 커져도 수행 속도가 급격히 느려진다.
Reference
반응형
'Algorithm' 카테고리의 다른 글
선택 정렬 (Selection Sort) 알고리즘 (with Python3) (0) | 2020.03.21 |
---|---|
하노이탑 알고리즘 구현 (with Python3) (0) | 2020.03.17 |
최대 공약수와 유클리드 알고리즘 (with Python3) (0) | 2020.03.17 |
팩토리얼 구하기 알고리즘 (with Python3) (0) | 2020.03.16 |
집합을 이용한 중복 제거 알고리즘 (with Python3) (0) | 2020.03.16 |