알고리즘은 어떤 목적을 달성하거나 결과물을 만들어 내기 위해 거쳐야 하는 일련의 과정들을 의미한다.
알고리즘을 해결할 때 해답을 찾는 과정은 다양하고 여러 가지 상황에 따른 알고리즘은 모두 다르기 때문에 효율적으로 문제를 해결하기 위해서는 시간 복잡도를 고민하여 문제를 해결한다.
시간 복잡도(Time Complexity)
시간복잡도의 가장 간단한 정의는 알고리즘의 성능을 설명하는 것이다.
다른 의미로는 알고리즘을 수행하기 위해 프로세스가 수행해야 하는 연산을 수치화한 것이다. 알고리즘의 로직을 코드로 구현할 때, 시간 복잡도를 고려한다는 것은 ‘입력값의 변화에 따라 연산을 실행할 때, 연산 횟수에 비해 시간이 얼마만큼 걸리는가?’라는 말이다.
→ 시간 복잡도에서 가장 중요하게 보는 것은 가장 큰 영향을 미치는 n의 단위이다.
Complexity | 1 | 10 | 100 |
---|---|---|---|
O(1) | 1 | 1 | 1 |
O(n) | 1 | 10 | 100 |
O(log n) | 0 | 2 | 5 |
O(n log n) | 0 | 20 | 461 |
O(n2) | 1 | 100 | 10000 |
O(2n) | 1 | 1024 | 1267650600228229401496703205376 |
💡 O(1)는 일정한 복잡도(Constant complexity)라고 하며, 입력값이 증가하더라도 시간이 늘어나지 않는다.
→ 입력값의 크기와 관계없이 문제를 해결하는 데 오직 한 단계만 처리한다.
👉 O(1)의 시간 복잡도를 가진 알고리즘
def O1_algorithm(arr, index){
return arr[index]
}
arr = [1, 2, 3, 4, 5]
index = 1
result = 01_algorithm(arr, index)
print(result)
💡 O(n)는 선형 복잡도(linear complexity)라고 부르며, 입력값이 증가함에 따라 시간 또한 같은 비율로 증가하는 것을 의미한다.
→ 문제를 해결하기 위해서 단계의 수와 입력값이 n이 1:1 관계를 맺는다.
👉 O(n)의 시간 복잡도를 가진 알고리즘
def On_algorithm(n){
for i in range(n):
print("do something for 1 second")
}
def another_On_algorithm(n){
for i in range(2n):
print("do something for 1 second")
}
💡 O(log n)는 로그 복잡도(logarithmic complexity)라고 부르며, Big-O 표기법 중 O(1) 다음으로 빠른 시간복잡도를 가진다.
→ 문제를 해결하기 위해서 필요한 단계들이 연산마다 특정 요인에 의해 줄어든다.
👉 O(log n) 의 시간 복잡도를 가진 알고리즘
def binary_search(li, item, first=0, last=None){
if not last:
last = len(li)
midpoint = (last, first) / 2 + first
if li[midpoint] == item:
return midpoint
elif li[midpont] > item:
return binary_search(li, item, first, midpoint)
else:
return binary_search(li, item, midpoint, last)
→ 매번 숫자를 제시할 때마다 경우의 수가 절반으로 줄어들기 때문에 최악의 경우에도 7번이면 원하는 숫자를 찾아낼 수 있게 된다.
→ BST의 값 탐색 또한 이와 같은 로직으로, O(log n)의 시간 복잡도를 가진 알고리즘(탐색기법)이다.
💡 O(n2)는 2차 복잡도(quadratic complexity)라고 부르며, 입력값이 증가함에 따라 시간이 n의 제곱수의 비율로 증가하는 것을 의미한다.
→ 문제를 해결하기 위한 단계의 수는 입력값 n의 제곱이다.
👉 O(n2)의 시간 복잡도를 가진 알고리즘
def O_quadratic_algorithm(n){
for i in range(n):
for j in range(n):
print("do something for 1 second")
}
def another_O_quadratic_algorithm(n){
for i in range(n):
for j in range(n):
for k in range(n):
print("do something for 1 second")
}
→ 2n, 5n을 모두 O(n)이라고 표현하는 것처럼, n3과 n5도 모두 O(n2)로 표기한다.
→ n이 커지면 커질수록 지수가 주는 영향력이 점점 사라지기 때문에 이렇게 표기한다.
💡 O(2n)는 기하급수적 복잡도(exponential complexity)라고 부르며, Big-O 표기법 중 가장 느린 시간복잡도를 가진다.
→ 구현한 알고리즘의 시간 복잡도가 O(2n)이라면 다른 접근 방식을 고민해 보는 것이 좋다.
👉 O(2n)의 시간 복잡도를 가진 알고리즘
def fibonacci(n){
if(n<=1):
return 1
return fibonacci(n-1)+fibonacci(n-2)
}
👍 시간복잡도를 구하는 Tip
Reference
https://hanamon.kr/알고리즘-time-complexity-시간-복잡도/
https://blog.chulgil.me/algorithm/