큰 문제의 답을 작은 문제를 통해 구할 수 있다는 의미
피보나치의 수열 - 다음 항이 그 전의 값과 그 다음값의 합으로 이루어 이루어지는값
1. Memoizaion으로 해결하는 방법(재귀)
def fib_memo(n, cache):
# base case
if n < 3:
return 1
# recursive case
# 이미 계산 된 값이 cache에 저장 되어 있으면 호출
if n in cache:
return cache[n]
# 만약 없으면 cache에 저장
cache[n] = fib_memo(n- 1, cache) + fib_memo(n - 2, cache)
return cache[n]
def fib_tab(n):
# 저장할 테이블 호출
fib_table = [0, 1, 1]
# 3번째 항 부터 앞의 두 핪으로 값을 추가해 n번째 수를 구한다.
for i in range(3, n + 1):
fib_table.append(fib_table[i - 1] + fib_table[i - 2])
return fib_table[n]
장점 : 간단하고 빠르다.
단점 : 최적의 답이 보장되지 않는다.
예제
수강 신청 분석
1. 최대한 많은 수업을 들을 수 있는 방법을 찾으려고 한다. 튜플 (2, 5) 는 각 수업시간의 시작과 끝을 의미 한다.
2. 수강 리스트 - [(4, 7), (2, 5), (1, 3), (8, 10), (5, 9), (2, 6), (13, 16), (9, 11), (1, 8)]
질문
1. 이 수강 리스트에는 최적부분 구조가 있습니까?
답 YES
-> 서로 서로 비교해서 구하면 구할 수 있음
따라서 Greedy Algorithm이 가능합니다.
def course_selection(course_list):
# 1. 리스트 상에서 튜플 두 번째항을 기준으로 정렬 을 해주기
sorted_list = sorted(couse_list, key = lambda x: x[1])
# 2. 나의 수강신청 리스트 만들기
my_couse_list = [couse_list[0]] -> 첫 번째 항은 제일 일찍 끝나는 수업이므로 넣어줌
# 3. 차례로 넣어주기 단 리스트에 있는 끝나는 시간과 남아있는 수업의 시작시간이 겹치면 안됨
for course in couse_list:
if course[0] < my_couse_list[-1][1]: -> 리스트에 있는 -1항 가장 마지막항의 [1]끝나는 시간
my_couse_list.appen(cousrse)
return course
출처 - codeit(알고리즘)