λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
CS/μ•Œκ³ λ¦¬μ¦˜

ν”Όλ³΄λ‚˜μΉ˜ 파이썬으둜 κ΅¬ν•˜λŠ” 3가지 μ•Œκ³ λ¦¬μ¦˜

by πŸŒ»β™š 2021. 10. 8.

ν”Όλ³΄λ‚˜μΉ˜ 파이썬 3가지 μ•Œκ³ λ¦¬μ¦˜

ν”Όλ³΄λ‚˜μΉ˜ μˆ˜μ—΄μ€ μ•„λž˜μ˜ μˆ˜μ‹μ€ λ§Œμ‘±ν•˜λŠ” μˆ˜μ—΄μž…λ‹ˆλ‹€.

λ°”λ‘œ 이전 μˆ«μžμ™€ κ·Έ μ „ 숫자의 합을 μ—°μ†ν•΄μ„œ κ΅¬ν•˜λŠ” μˆ˜μ—΄μ΄κ³  μ•„λž˜μ™€ 같이 μ§„ν–‰λ©λ‹ˆλ‹€.

 

이번 κΈ€μ—μ„œλŠ” μ‹œκ°„ λ³΅μž‘λ„μ— λ”°λ₯Έ ν”Όλ³΄λ‚˜μΉ˜ μˆ˜μ—΄μ„ κ΅¬ν•˜λŠ” λŒ€ν‘œμ μΈ 3가지 μ•Œκ³ λ¦¬μ¦˜μ— λŒ€ν•΄μ„œ μ•Œμ•„λ³΄λ„λ‘ ν•˜κ² μŠ΅λ‹ˆλ‹€.

  • μž¬κ·€ν•¨μˆ˜ 이용 - μ‹œκ°„λ³΅μž‘λ„ O(n^2)
  • 동적 κ³„νšλ²• 이용 - μ‹œκ°„λ³΅μž‘λ„ O(n)
  • ν–‰λ ¬ 멱법 이용 - μ‹œκ°„λ³΅μž‘λ„ O(log n)

 

μž¬κ·€ν•¨μˆ˜ 이용

첫번 μ§Έ 방법은 μž¬κ·€ν•¨μˆ˜λ₯Ό μ΄μš©ν•˜λŠ” λ°©λ²•μž…λ‹ˆλ‹€.

def fibo(n):
    if n in (1,2):
        return 1
    return fibo(n-1) + fibo(n-2)

print(fibo(8))

κ°€μž₯ κ°„λ‹¨ν•œ λ°©λ²•μ΄μ§€λ§Œ... μž¬κ·€λ‘œ λ‘κ°œμ˜ λΆ„κΈ°κ°€ κ³„μ†ν•΄μ„œ 생기기 λ•Œλ¬Έμ— μ‹œκ°„λ³΅μž‘λ„κ°€ O(n^2)둜 맀우 λΉ„νš¨μœ¨μ μ΄λ‹€. ν”Όλ³΄λ‚˜μΉ˜ μˆ˜μ—΄μ„ κ΅¬ν•˜λŠ” μ•Œκ³ λ¦¬μ¦˜ 문제λ₯Ό ν’€ λ•Œ... μž¬κ·€ν•¨μˆ˜λ‘œ ν’€λ©΄ λŒ€λΆ€λΆ„ νš¨μœ¨μ„± ν…ŒμŠ€νŠΈλŠ” ν†΅κ³Όν•˜μ§€ λͺ»ν•  것이닀.

 

 

동적 κ³„νšλ²• 이용

def fibo(n):
    cache = [0, 1]
    for i in range(2, n+1):
        cache.append(cache[i-1] + cache[i-2])
    return cache[n]

print(fibo(8))

동적 κ³„νšλ²•μ„ μ‚¬μš©ν•˜λ©΄ μž¬κ·€λ‘œ ν–ˆμ„ λ•Œ μ€‘λ³΅λ˜λŠ” 계산과정을 μž¬μ‚¬μš©ν•  수 μžˆλ‹€. 이러면 nκΉŒμ§€ ν•œλ²ˆμ”©λ§Œ 계산해주면 문제λ₯Ό ν•΄κ²°ν•  수 μžˆμ–΄ μ‹œκ°„ λ³΅μž‘λ„κ°€ O(n)이 λœλ‹€. λŒ€λΆ€λΆ„μ˜ ν”Όλ³΄λ‚˜μΉ˜ μ•Œκ³ λ¦¬μ¦˜ λ¬Έμ œλ“€μ€ 이정도 νš¨μœ¨μ„ κ°–κ³  ν•΄κ²°ν•  수 μžˆμ§€λ§Œ... λͺ‡λͺ‡ λ¬Έμ œλ“€μ—μ„œλŠ” 더 큰 λ²”μœ„μ˜ input이 주어지고 더 λΉ λ₯Έ μ•Œκ³ λ¦¬μ¦˜μ„ μš”κ΅¬ν•˜λŠ” λ¬Έμ œλ“€μ΄ μžˆμŠ΅λ‹ˆλ‹€. 이런 λ¬Έμ œλŠ” ν–‰λ ¬ 멱법을 톡해 ν•΄κ²°ν•  수 μžˆλ‹€.

 

 

ν–‰λ ¬ 멱법 이용

ν–‰λ ¬ 멱법은 점화식을 ν–‰λ ¬ν™” μ‹œμΌœμ„œ ν‘ΈλŠ” 방법 μž…λ‹ˆλ‹€. ν–‰λ ¬ 멱법을 μžμ„Ένžˆ 보기 전에... 행렬을 μ΄μš©ν•΄μ„œ μ‹œκ°„ λ³΅μž‘λ„λ₯Ό O(log N)κΉŒμ§€ 쀄일 수 컨셉은 μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.

κ·Έλ¦Ό 1

ν–‰λ ¬μ˜ κ±°λ“­μ œκ³±μ„ μ΄μš©ν•˜λ©΄ μš°μ„  μ‹œκ°„ λ³΅μž‘λ„λ₯Ό O(log n)으둜 맞좜 수 μžˆμŠ΅λ‹ˆλ‹€. μœ„μ˜ μ˜ˆμ‹œλ₯Ό 봀을 λ•Œ 8μ΄λ‚˜ 11번째 ν”Όλ³΄λ‚˜μΉ˜ μˆ˜μ—΄μ˜ 수λ₯Ό κ΅¬ν•œλ‹€κ³  ν–ˆμ„ λ•Œ 동적 κ³„νšλ²•μ„ μ‚¬μš©ν–ˆλ˜ κ²ƒμ²˜λŸΌ NκΉŒμ§€ ν•˜λ‚˜μ”© λͺ¨λ‘ κ³„μ‚°ν•΄λ³΄λŠ”κ²Œ μ•„λ‹ˆλΌ... μ ˆλ°˜μ”© μ€„μ—¬κ°€λ©΄μ„œ κ³„μ‚°ν•˜κΈ° λ•Œλ¬Έμ— μ‹œκ°„ λ³΅μž‘λ„λ₯Ό O(log n)으둜 λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€.

 

점화식 λ³€ν˜•

κ·Έλ ‡λ‹€λ©΄ μ–΄λ–»κ²Œ???... 행렬을 μ΄μš©ν•΄μ„œ μ•Œκ³ λ¦¬μ¦˜μ„ λ§Œλ“€ 수 μžˆλŠ” κ²ƒμΌκΉŒμš”? 점화식을 μ΄μš©ν•΄μ„œ 절차λ₯Ό λ³΄μ—¬λ“œλ¦¬κ² μŠ΅λ‹ˆλ‹€.

 

κ·Έλ¦Ό 2

λ¨Όμ € ν”Όλ³΄λ‚˜μΉ˜μ˜ 점화식을 ν–‰λ ¬μ˜ κ³±μ…‰μœΌλ‘œ μ‚¬μš©ν•˜κΈ° μœ„ν•΄ λ³€κ²½ν•˜λ©΄...  κ·Έλ¦Ό 2와 같이 두가지 식을 λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€.

 

κ·Έλ¦Ό 3

κ·Έλ¦Ό 2μ—μ„œ λ³Έ 두 식을 ν–‰λ ¬μ˜ κ³±μ…ˆμœΌλ‘œ ν‘œν˜„ν•˜λ©΄ κ·Έλ¦Ό 3κ³Ό 같이 ν•  수 μžˆμŠ΅λ‹ˆλ‹€. ν–‰λ ¬ ν˜•νƒœλ‘œ λΆ„λ¦¬ν•˜λ©΄ λ‹€μ‹œ ν•¨μˆ˜μ˜ 행렬이 λ‚˜μ˜€λŠ”λ°... 이 ν•¨μˆ˜ 행렬도 μš°ν•­μ˜ ν•¨μˆ˜μ™€ 같은 ν˜•νƒœμž…λ‹ˆλ‹€. 일단 λ‹€μ‹œ λΆ„ν•΄λ₯Ό 해보면 μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.

 

κ·Έλ¦Ό 4

ν•¨μˆ˜ 행렬을 λ‹€μ‹œ λΆ„ν•΄ν•˜λ©΄ λ˜‘κ°™μ€ νŒ¨ν„΄μœΌλ‘œ 뢄리가 λ˜λ©΄μ„œ μ΅œμ’…μ μœΌλ‘œ μ‚¬μš©ν•  식이 λ‚˜μ˜΅λ‹ˆλ‹€.

 

μ΅œμ’… 식

κ·Έλ¦Ό 3κ³Ό κ·Έλ¦Ό 4의 식을 정리해보면 μœ„μ˜ μ΅œμ’… μ‹μœΌλ‘œ μ •λ¦¬λ©λ‹ˆλ‹€. ν•¨μˆ˜κ°€ λ“€μ–΄ μžˆλŠ” ν–‰λ ¬μ˜ μΈμžκ°€ 1,0이 될 λ•ŒκΉŒμ§€ 숫자 ν˜•νƒœλ‘œ λ˜μ–΄ μžˆλŠ” ν–‰λ ¬μ˜ κ±°λ“­μ œκ³±μ„ n만큼 μ§„ν–‰ν•©λ‹ˆλ‹€.

 

 

풀이

μœ„μ˜ 풀이 λ‚΄μš©μ„ 정리해보면 μ½”λ“œν™” μ‹œμΌœμ•Όν•  뢀뢄은 μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.

  • ν–‰λ ¬μ˜ κ±°λ“­μ œκ³±
    • μ§μˆ˜μ™€ ν™€μˆ˜ μΌλ•Œ 차이가 μžˆλ‹€.
  • ν–‰λ ¬μ˜ 멱법
    • 숫자 ν˜•νƒœμ˜ 행렬을 κ±°λ“­μ œκ³±ν•  수 μžˆλ„λ‘ν•œλ‹€.
    • f(1), f(0)값은 각각 1 κ³Ό 0으둜 값이 μ •ν•΄μ Έ μžˆμ–΄ κ³±ν•΄μ£ΌλŠ” μž‘μ—…μ€ μƒλž΅ν•˜κ³  ν–‰λ ¬ A[0][0] μœ„μΉ˜μ˜ 값을 λ°˜ν™˜ν•œλ‹€.
  • ν”Όλ³΄λ‚˜μΉ˜ μˆ˜μ—΄μ€  첫 번째, λ‘λ²ˆμ§Έ μžλ¦¬κ°€ 1둜 μ‹œμž‘ν•˜μ—¬ ν•΄λ‹Ή λ°©μ‹μœΌλ‘œ ν•  λ•ŒλŠ” μ‹€μ œλ‘œ ν•¨μˆ˜μ— λ„£λŠ” 값에 -1ν•΄μ„œ λ„£λŠ”λ‹€.

 

def matrix_mult(A, B):
    temp = [[0] * 2 for _ in range(2)]
    for i in range(2):
        for j in range(2):
            for k in range(2):
                temp[i][j] += (A[i][k] * B[k][j])
    return temp

def matrix_pow(n, M):
    if n == 1:
        return M
    if n % 2 == 0:
        temp = matrix_pow(n//2, M)
        return matrix_mult(temp, temp)
    else:
        temp = matrix_pow(n-1, M)
        return matrix_mult(temp, M)

A = [[1, 1], [1, 0]]
print(matrix_pow(8-1, A)[0][0])

ν–‰κ²°μ˜ κ³±μ…‰ μž‘μ—…μ„ ν•  수 μžˆλŠ” matrix_mult ν•¨μˆ˜μ™€ M의 nμ œκ³±μ„ ꡬ할 수 μžˆλŠ” matrix_powν•¨μˆ˜λ₯Ό μ΄μš©ν•΄μ„œ 행렬을 μ΄μš©ν•œ ν”Όλ³΄λ‚˜μΉ˜ μˆ˜μ—΄μ„ ꡬ할 수 μžˆλ‹€. ν•΄λ‹Ή λ°©λ²•μœΌλ‘œ ν•˜λ©΄ μ‹œκ°„ λ³΅μž‘λ„λ₯Ό O(log n)κΉŒμ§€ 쀄일 수 μžˆμ–΄ λ‹€λ£¨λŠ” 숫자의 λ²”μœ„κ°€ 컀질수둝 맀우 큰 νš¨μœ¨μ„ 얻을 수 μžˆλ‹€.

 

 

 

λŒ“κΈ€