본문 바로가기
내가 공부하려고 올리는/TIL

2022-07-22 TIL

by 결딴력 2022. 7. 22.
반응형

 

☝ 알고리즘

  • 반복문을 돌려서 반복문의 결과로 나오는 값 중 최댓값이나 최솟값을 구해야 하는 경우,
    반복문 내에서 반복문의 결과를 받을 변수를 선언하고,
    반복문 밖에서는 반복문의 결과를 받아온 변수와 비교하여 최종 값을 저장할 변수를 설정한다.
  • 예시
# 1부터 10까지 반복문을 돌려 최댓값을 찾는 경우

#최종값을 받을 변수 선언
result = 0

for i in range(1, 11) :

	#반복문의 리턴값을 받을 변수 선언
    count = 0
    
	for x in range(n) :
    	for y in range(m) :
        	#로직 실행 생략
			count += 1
    
    #반복문 실행 결과값과 외부의 result(처음은 0)과 max 비교
    result = max(count, result)
    
    #실행 결과 외부의 result 값 변경

 

 

 재귀 함수를 사용해 벽 세우기 코드

  • 랜덤한 3곳의 좌표에 벽을 세워야 한다고 가정할 때 재귀 함수를 사용해 모든 좌표를 얻을 수 있다.
  • 예시
def dfs(count):
    global result
    if count == 3:
        for i in range(n):
            for j in range(m):
                temp[i][j] = graph[i][j]
        for i in range(n):
            for j in range(m):
                if temp[i][j] == 2:
                    virus(i,j)
        result = max(result,score())
        return

    #빈공간에 울타리 설치 
    #DFS 이용해 울타리 설치 가능한 모든경우의 수 탐색
    for i in range(n):
        for j in range(m):
            if graph[i][j] == 0:
                graph[i][j] = 1
                count+=1
                dfs(count)
                graph[i][j] = 0
                count-=1
                #맵의 상태가  count값이 3이 된 이전과 이후가 계속해서 바뀌기 때문에 
                #모든 울타리 설치 경우의 수를 구할 수 있다.

 

 

 정렬

  • 데이터를 특정한 기준에 따라 순서대로 나열하는 것
  • 정렬 알고리즘은 이진 탐색(Binary Search)의 전처리 과정
  • 대표적인 정렬 알고리즘 '선택 정렬', '삽입 정렬', '퀵 정렬', '계수 정렬'

 

 선택 정렬

  • 두 개의 데이터 중 작은 것을 선택해서 정렬하는 방식
  • 선택 정렬 예시
array = [7, 5, 9, 0, 3, 1, 6, 2, 4, 8]

for i in range(len(array)) :
  min_idx = i
  for j in range(i+1, len(array)) :
    if array[min_idx] > array[j] :
      min_idx = j
  array[i], array[min_idx] = array[min_idx], array[i]

print(array)
  • array[i], array[min_idx] = array[min_idx], array[i] => 스와프(Swap) 코드
  • O(N*2)의 시간 복잡도

 

 삽입 정렬

  • 특정 데이터를 특정 위치에 삽입하는 정렬 방식
  • 선택 정렬에 비해 구현 난도가 높지만 선택 정렬에 비해 실행 시간 측면에서 더 효율적
  • 삽입 정렬은 필요할 때만 위치를 바꾸므로 데이터가 정렬되어 있을수록 효율적
  • O(N*2)의 시간 복잡도
  • 삽입 정렬 예시
array = [7, 5, 9, 0, 3, 1, 6, 2, 4, 8]

for i in range(1, 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

print(array)

 

 퀵 정렬

  • 기준을 설정한 다음 큰 수와 작은 수를 교환한 후 리스트를 반으로 나누는 방식
  • 퀵 정렬에서는 큰 수와 작은 수를 교환하기 위한 기준으로 '피벗(Pivot)'이 사용됨
  • 피벗을 설정하고 리스트를 분할하는 방법에 따라 퀵 정렬이 구분됨
  • O(NlogN)의 시간 복잡도

 

 호어 분할(Hoare Partition)

  • 리스트에서 첫 번째 데이터를 피벗으로 설정
  • 리스트의 첫 번째 데이터를 피벗으로 설정하고
    왼쪽에서부터 피벗보다 큰 수를 선택, 오른쪽에서부터 피벗보다 작은 수를 선택
  • 이후 두 데이터의 위치를 변경
  • 위 과정을 반복 후에 왼쪽에서 찾는 값과 오른쪽에서 찾는 값이 엇갈리는 경우
    작은 데이터와 피벗을 변경
  • 이렇게 피벗이 이동한 상태에서 피벗을 기준으로 왼쪽은 피벗보다 작고,
    오른쪽은 피벗보다 크게 데이터가 정렬되는데 이것을 분할 혹은 파티션이라고 함
  • 각 파티션에 대해 다시 해당 과정을 반복
  • 같은 과정을 파티션 내에서 반복하기 때문에 재귀 함수로 구현할 수 있다.
  • 퀵 정렬 재귀 함수의 종료 조건은 리스트의 개수가 1개일 때
  • 퀵 정렬 예시
array = [7, 5, 9, 0, 3, 1, 6, 2, 4, 8]

def quick_sort(array) :
  #원소가 1개인 경우 종료
  if len(array) <= 1 :
    return array

  pivot = array[0]
  tail = array[1:]

  left_side = [x for x in tail if x <= pivot]
  right_side = [x for x in tail if x > pivot]

  return quick_sort(left_side) + [pivot] + quick_sort(right_side)

print(quick_sort(array))

 

 계수 정렬

  • 특정한 조건이 부합할 때 사용하는 매우 빠른 정렬 알고리즘
  • 모든 데이터가 양의 정수이고 데이터의 개수가 N개, 데이터 중 최댓값이 K일 때,
    계수 정렬은 최악의 경우에도 수행 시간 O(N+K)를 보장
  • 일반적으로 가장 큰 데이터와 가장 작은 데이터의 차이가 10**6을 넘지 않아야 효과적
  • 계수 정렬은 별도의 리스트를 선언하고 리스트에 정렬 정보를 담는 방식
  • 계수 정렬은 데이터의 크기가 한정되어 있고, 데이터의 크기가 많이 중복되어 있을수록 유리
  • 계수 정렬의 공간 복잡도는 O(N+K)
  • 계수 정렬 예시
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=' ')

 

 

 튜플 데이터 정렬

  • 튜플 데이터를 입력받고 정렬하여 출력하기 예시
n = int(input())
graph=[]
for i in range(n) :
  input_data = input().split()
  graph.append((input_data[0], int(input_data[1])))

graph = sorted(graph, key=lambda student: student[1])

for student in graph :
  print(student[0], end=' ')

 

 

 이진 탐색

  • 배열 내부의 데이터가 정렬되어 있어야 사용할 수 있다.
  • 이진 탐색은 위치를 나타내는 변수 3개를 사용 👉 탐색하고자 하는 범위의 시작점, 끝점, 중간점
  • 중간 인덱스가 소수점이 붙는 경우 소수점 이하를 버린 인덱스를 중간점으로 설정한다.
  • 이진 탐색의 시간 복잡도는 O(longN)
  • 처리해야 할 데이터의 개수나 값이 1,000만 단위 이상으로 넘어가면 이진 탐색을 고려해보는 것이 좋음
  • 이진 탐색 재귀 함수로 구현 예시
def binary_search(array, target, start, end) :
  if start > end :
    return None
    
  mid = (start+end) // 2

  if array[mid] == target :
    return mid
  elif array[mid] > target :
    return binary_search(array, target, start, mid - 1)
  else :
    return binary_search(array, target, mid + 1, end)


n, target = list(map(int, input().split()))
array = list(map(int, input().split()))

result = binary_search(array, target, 0, n-1)
if result == None :
  print("원소가 존재하지 않습니다.")
else :
  print(result+1)

 

 

 트리 구조

  • 트리는 부모 노드와 자식 노드의 관계로 표현
  • 트리의 최상단 노드를 루트 노드라 함
  • 트리의 최하단 노드를 단말 노드라 함
  • 트리의 일부도 트리 구조이며, 이를 서브 트리라 함

 

 

 이진 탐색 트리

  • 트리 자료구조 중에서 가장 간단한 형태의 이진 탐색 트리
  • 이진 탐색 트리의 부모 노드는 왼쪽 자식 노드보다 크다
  • 이진 탐색 트리의 부모 노드는 오른쪽 자식 노드보다 작다
  • 이진 탐색 트리에서 
반응형

'내가 공부하려고 올리는 > TIL' 카테고리의 다른 글

2022-07-29 TIL  (0) 2022.07.30
2022-07-27 TIL  (0) 2022.07.27
2022-07-26 TIL  (0) 2022.07.27
2022-07-21 TIL  (0) 2022.07.21
2022-07-20 TIL  (0) 2022.07.21

댓글