저번 이코테 정리에 이어서 이번에도 이코테 정리를 해보고자 한다!! 저번 강의들을 통해서 이번에는 그 다음 강의들을 마저 좀더 정리해보고자 한다!! 강의 내용이 조금 분량이 있어서 나눠서 3,4개 정도로 게시글을 작성할 예정이다.
마찬가지로 정리한 내용을 바탕으로 앞으로 파이썬을 잘 사용할 수 있도록 하구 적용해볼 수 있도록 문제를 다양하게 풀어볼 예정이다!!
참고 강의 링크! 👉 https://www.youtube.com/playlist?list=PLRx0vPvlEmdAghTr5mXQxGpHjWqSz0dgC
: 데이터를 특정한 기준에 따라 순서대로 나열
선택 정렬 : 이중 반복문을 이용하여 가장 작은 원소를 찾아 앞쪽으로 자리를 바꾸면서 정렬
for i in range(len(array)):
min_index = i
for j in range(i + 1, len(array)):
if array[min_index] > array[j]:
min_index = j
array[i], array[min_index] = array[min_index], array[i]
→ 시간 복잡도는 N번만큼 가장 작은 수를 찾아서 맨앞으로 보내야 함.
이는 빅오 표기법에 따라서 O(N^2)으로 작성함
삽입 정렬 : 처리되지 않은 데이터를 하나씩 골라 적절한 위치에 삽입함.
for i in range(len(array)):
for j in range(i, 0, -1):
if array[j] > array[j - 1]:
array[j], array[j - 1] = array[j - 1], array[j]
else :
break
→ 시간복잡도는 선택 정렬처럼 반복문이 두 번 중첩되서 O(N^2) 중첩됨
데이터가 거의 정렬되어 있는 경우면 매우 빠르게 동작 → 거의 O(N)임
퀵 정렬 : 기준 데이터를 설정하고 그 기준보다 큰 데이터와 작은 데이터의 위치를 바꾸는 방법
→ 시상적인 경우 분할이 절반씩 이루어지면 전체 연산 횟수가 O(NlogN)을 기대 가능(너비 * 높이)
시간복잡도가 평균의 경우 O(NlogN) 으로 가지나 최악의 경우는 O(N^2) 의 시간 복잡도
→ 모두 이미 정렬된 배열을 퀵 정렬로 실행하려고 할 때 최악의 경우
def quick_sort(array, start, end):
if start >= end:
return
pivot = start
left = start + 1
right = end
while left <= right :
while(left < end and array[left] <= array[pivot]):
left += 1
while(right > start and array[right] >= array[pivot]):
right += 1
if(left > right):
array[right], array[pivot] = array[pviot], array[right]
else :
array[left], array[right] = array[right], array[left]
quick_sort(array, start, right - 1)
quick_sort(array, right + 1, end)
quick_sort(array, 0, len(array) - 1)
계수 정렬 : 특정한 조건이 부합할 때만 사용할 수 있지만 매우 빠르게 동작하는 정렬알고리즘
array = [7, 5, 9, 0, 3, 1, 6, 2, 9, 1, 4, 8 , 0, 5, 2]
count = [0] * (max(array) + 1)
for i in range(len(array)):
count[array[i]] += 1
for i in range(len(count)):
for j in range(count[i]):
print(i, end=' ')
시간 복잡도 : O(N + K)
순차 탐색 : 리스트 안에 있는 특정한 데이터를 찾기 위해 앞에서부터 데이터를 하나씩 확인
이진 탐색 : 정렬 되어 있는 리스트에서 탐색 범위를 절반씩 좁혀가며 데이터를 탐색
def binary_search(array, target, start, end):
while start <= end:
mid = (start + end) // 2
if array[mid] == target:
return mid
elif array[mid] > target:
end = mid - 1
else:
start = mid + 1
return None
떡볶이 떡 만들기
start = 0
end = max(array)
result = 0
while start <= end:
total = 0
mid = (start + end) // 2
for x in array :
if x > mid:
total += x - mid
if total < m:
end = mid - 1
else:
result = mid
start = mid + 1
정렬된 배열에서 특정 수의 개수 구하기
from bisect import bisect_left, bisect_right
def count_by_range(array, left_value, right_value):
right_index = bisect_right(array, right_value)
left_index = bisect_left(array, left_value)
return right_index - lef_index
n, x = map(int, input().split())
array = list(map(int, input().split()))
count = count_by_range(array, x, x)
if count == 0:
print(-1)
else:
print(count)
다이나믹 프로그래밍 : 메모리를 적절히 사용하여 수행시간 효율성을 비약적으로 향상시키는 방법 → 이미 계산된 결과는 별도의 메모리 영역에 저장
다이나믹 프로그래밍의 사용 조건
피보나치 수열 - 1, 1, 2, 3, 5, 8, 13 …
점화식 : 인접한 항들 사이의 관계식 의미
def fibo(x):
if x == 1 or x == 2:
return 1
return fibo(x - 1) + fibo(x - 2)
단순 재귀 함수 코드 (위처럼) 하면 지수 시간 복잡도를 가지게 됨(동일한 호출이 여러 번 호출 되는 것 확인 가능)
빅 오 표기법으로 : O(2^N) 시간 복잡도
메모이제이션(탑다운) : 한번 계산한 결과를 메모리 공간에 메모하는 기법
<탑다운 - 하향식, 보텀업 - 상향식>
전형적인 다이나믹 프로그래밍의 전형적인 형태는 보텀업으로 결과 저장용 리스트는 DP 테이블이라고 부름
탑다운 방식
d = [0] * 100
def fibo(x):
if x == 1 or x == 2:
return 1
if d[x] != 0:
return d[x]
d[x] = fibo(x - 1) + fibo(x - 2)
return d[x]
보텀법 방식
d = [0] * 100
d[1] = 1
d[2] = 1
n = 99
for i in range(3, n + 1):
d[i] = d[i - 1] + d[i - 2]
메모이제이션을 이용한 피보나치 수열 함수의 시간 복잡도는 O(N)임
→ 둘다 최적 부분 구조를 가질 때 사용하나 부분문제의 중복에서는 다름 (분할정복은 X)
분할이 이루어진 뒤에 그 문제는 다시 처리하지 않음
주어진 문제가 DP 유형임을 파악하는 것이 중요함.
다른 알고리즘(그리디, 구현, 완전 탐색)으로 안 풀리면 다이나믹 프로그래밍으로 문제 접근하기
탑다운 → 보텀업으로 코드 개선하는 방법 사용해보기
개미 전사
i 번째 식량창고에 대해서 털지 안 털지 여부를 결정하여 문제 해결
ai = max(ai-1, ai-2 + ki)
→ i-3 번째 이하는 고려 필요 없음
n = int(intpu()
array = list(map(int, input().split()))
d = [0] * 100
d[0] = array[0]
d[1]= max(array[0], array[1])
for i in range(2, n):
d[i] = max(d[i - 1], d[i - 2] + array[i])
print(d[n - 1])
1로 만들기
정수 x에 사용하는 연산 4가지, 4개를 적절히 사용하여 1로 만들기
ai = min(ai-1, ai/2, ai/3, ai/5) + 1
x = int(input()
d = [0] * 30001
for i in range(2, x + 1):
d[i - 1] = d[i -1] + 1
if i % 2 == 0:
d[i] = min(d[i], d[i // 2] + 1)
if i % 3 == 0:
d[i] = min(d[i], d[i // 3] + 1)
if i % 5 == 0:
d[i] = min(d[i], d[i // 5] + 1)
print(d[x])
이렇게 이번에는 이코테의 정렬 알고리즘, 이진 탐색, DP의 방법들을 살펴 보았다. 다음에는 다른 내용의 알고리즘을 정리하고자 한다!! 인제 OPIC 시험도 봐서 앞으로는 개발공부에 더 집중해볼 예정이다. 또는! 한주만 쉬고 컴활을 공부할 수도 있고 일단 담주에 여행 다녀오기 전에 최대한 디자인과 코테 준비를 진행해보고자 한다.
파이썬을 이용하여 백준의 쉬운 문제를 차근차근히 풀고 있어서 우선 내가 기억하면 좋을 파이썬의 라이브러리나 알고리즘을 사용하였을 때 그 문제를 velog에 정리하고자 한다!!
화이팅~!