반응형
스파르타 코딩클럽 내일배움캠프 AI 웹개발자양성과정 3회차
2022.09.19. 14일차 - TIL
1. 알고리즘, 자료구조 강의
- Array : 크기가 정해진 연속된 데이터 공간, 데이터 접근이 빠르며(O(1)) 데이터 추가 시 모든 공간이 다 찼다면 새로운 공간을 할당하고, 중간에 요소 삽입/삭제가 어렵다(O(n)) -> 모든 요소를 이동시켜야 한다
- Linked List: 크기가 정해지지 않은 데이터 공간, 삽입과 삭제가 빈번한 문제에 사용하기 좋으며 모든 공간이 다 찼어도 맨 뒤의 노드만 동적으로 추가 가능하다. 특정 데이터 조회에 O(n)의 시간이 필요하다.
- 파이썬의 list는 내부적으로 동적 배열을 사용해 배열, 링크드 리스트 모두로 사용 가능
- linked list 구현
# 노드 클래스 정의
class Node:
def __init__(self, data):
self.data = data
self.next = None
# 링크드 리스트 클래스 정의
class LinkedList:
# 받은 값으로 노드를 생성하고, head에 저장
def __init__(self, value):
self.head = Node(value)
# 끝에 노드를 추가하는 메소드
def append(self, value):
cur = self.head
while cur.next is not None: # 가장 마지막 노드 위치 찾기
cur = cur.next
cur.next = Node(value) # 받은 값으로 노드를 생성하고, next에 다음 노드 저장
# 특정 원소 반환 메소드
def get_node(self, index):
node = self.head
count = 0
while count < index:
node = node.next
count += 1
return node
# 중간에 원소 삽입 메소드
def add_node(self, index, value):
new_node = Node(value) # 새로운 노드 생성
# index - 1 이 0이 될 경우의 예외 처리
if index == 0:
new_node.next = self.head
self.head = new_node
return
node = self.get_node(index - 1) # 삽입을 원하는 위치의 노드 가져오기
next_node = node.next # 해당 노드의 next값을 따로 저장
node.next = new_node # 이전 노드가 가지고 있던 다음 노드를 가져와
new_node.next = next_node # 새로운 노드의 next에 추가
# 링크드 리스트 원소 삭제 메소드
def delete_node(self, index):
if index == 0:
self.head = self.head.next
return
node = self.get_node(index - 1)
node.next = node.next.next
# 링크드 리스트 전체 출력 메소드
def print_all(self):
cur = self.head
while cur is not None:
print(cur.data)
cur = cur.next
- 순차탐색 : 처음부터 하나씩 수를 비교해 값을 찾는다. -> O(n)
- 이진탐색 : 정렬된 수에서 중간값과 비교해 값이 크면 우측에서, 값이 작으면 좌측에서 다시 탐색 반복 -> O(logn)
finding_target = 14
finding_numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
def is_existing_target_number_binary(target, array):
current_min = 0
current_max = len(array) - 1
current_guess = (current_min + current_max) // 2
while current_min <= current_max:
if array[current_guess] == target:
return True
elif array[current_guess] < target:
current_min = current_guess + 1
else:
current_max = current_guess - 1
current_guess = (current_min + current_max) // 2
return False
result = is_existing_target_number_binary(finding_target, finding_numbers)
print(result)
- 재귀함수 : 자기 자신을 호출하는 함수, 반드시 빠져나가는 지점을 명확히 정해줘야 한다.
- 팩토리얼
def factorial(n):
if n == 1:
return 1
return n * factorial(n - 1)
print(factorial(60))
- 회문 검사(앞으로 읽으나 뒤로 읽으나)
input = "abcba"
def is_palindrome(string):
if len(string) <= 1:
return True
if string[0] != string[-1]:
return False
return is_palindrome(string[1:-1]) # 밖에 두 문자를 빼고 나머지를 재귀함수로 돌림
print(is_palindrome(input))
- 2주차 과제
# 문제 1: 링크드 리스트의 끝에서 k번째 값을 반환하시오.
# 노드 클래스 선언
class Node:
def __init__(self, arg_data):
self.data = arg_data # 노드 값 저장
self.next = None # 다음 노드를 가리킬 지표
# 링크드 클래스 선언
class LinkedList:
# 먼저 노드 클래스 생성 후 head에 저장
def __init__(self, value):
self.head = Node(value)
# 노드를 추가해 리스트에 연결하는 메서드
def append(self, value):
cur = self.head # 현재 위치를 리스트의 헤드로 초기화
while cur.next is not None: # 현재 위치가 리스트의 끝에 도달할 때까지 반복
cur = cur.next # 현재 위치값 변경
cur.next = Node(value) # 마지막 위치에 도달하면 다음을 가리키는 지표에 새로운 노드 추가
def get_kth_node_from_last(self, k):
# 방법1) 리스트의 길이를 구해 위치 구하기
length = 1
cur = self.head
# linked의 길이를 알기 위한 반복문
while cur.next is not None:
cur = cur.next
length += 1
end_length = length - k # 구하고자 하는 인덱스의 (앞에서의) 위치
cur = self.head
for _ in range(end_length):
cur = cur.next
return cur
'''방법2) k만큼 떨어진 포인터 두개 설정(slow와 fast)
slow = self.head
fast = self.head
# k만큼 떨어진 곳에 fast 위치
for i in range(k):
fast = fast.next
while fast is not None:
slow = slow.next
fast = fast.next
return slow
'''
linked_list = LinkedList(6)
linked_list.append(7)
linked_list.append(8)
print(linked_list.get_kth_node_from_last(2).data) # 7이 나와야 합니다!
# 문제 2: 현재 주문 가능한 상태인지 확인
shop_menus = ["만두", "떡볶이", "오뎅", "사이다", "콜라"]
shop_orders = ["오뎅", "콜라", "만두"]
'''방법1) 정렬 후 이진탐색
def is_available_to_order(menus, orders):
menus.sort() # menus 정렬!
for order in orders:
# 주문이 메뉴에 없으면 False 리턴
if not is_existing_target_number_binary(order, menus):
return False
return True
# 이진 탐색 함수
def is_existing_target_number_binary(target, array):
current_min = 0
current_max = len(array) - 1
current_guess = (current_min + current_max) // 2
while current_min <= current_max:
if array[current_guess] == target:
return True
elif array[current_guess] < target:
current_min = current_guess + 1
else:
current_max = current_guess - 1
current_guess = (current_min + current_max) // 2
return False
'''
# 방법 2) 집합으로 바꿔 in 으로 확인
def is_available_to_order(menus, orders):
menu_set = set(menus)
for order in orders:
if order not in menu_set:
return False
return True
result = is_available_to_order(shop_menus, shop_orders)
print(result)
# 문제 3: 음이 아닌 정수 배열이 있을 때 이 수를 적절히 더하거나 빼서 특정한 숫자를 만들려고 할 때 방법의 수를 반환
# n 길이의 배열에서 더하거나 뺀 경우의 수는 n-1 길이의 배열에서 마지막 원소를 더하거나 뺀 경우의 수를 추가
numbers = [1, 1, 1, 1, 1]
target_number = 3
result_count = 0 # target 을 달성할 수 있는 모든 방법의 수를 담기 위한 변수
def get_count_of_ways_to_target_by_doing_plus_or_minus(array, target, current_index, current_sum):
if current_index == len(array): # 탈출 조건 -> 현재 인덱스가 array 끝에 도달할 때
if current_sum == target: # 합계가 타겟이 되면
global result_count
result_count += 1 # 합계 카운트 증가
return
get_count_of_ways_to_target_by_doing_plus_or_minus(array, target, current_index+1, current_sum+array[current_index])
get_count_of_ways_to_target_by_doing_plus_or_minus(array, target, current_index+1, current_sum-array[current_index])
return 5
get_count_of_ways_to_target_by_doing_plus_or_minus(numbers, target_number, 0, 0)
# current_index 와 current_sum 에 0, 0을 넣은 이유는 시작하는 총액이 0, 시작 인덱스도 0이니까 그렇습니다!
print(result_count)
- 버블 정렬 : 첫 번째와 두 번째, 두 번째와 세 번째, 세 번째와 네 번째, .. , (마지막-1)와 마지막 자료를 비교하며 교환해 자료를 정렬하는 방법
-> 오름차순의 경우 1단계로 끝까지 도달하면 가장 우측에 가장 큰 수가 위치, 내림차순의 경우 1단계로 끝까지 도달하면 가장 우측에 가장 작은 수가 위치
-> O(n^2) 시간
# 1단계 : [4, 2, 6, 1, 9] -> [0]과 [1] 비교, [1]과 [2] 비교, [2]와 [3] 비교, [3]과 [4] 비교(이때 큰 값을 오른쪽에 위치시킴)
# 2단계 : [2, 4, 1, 6, 9] -> [0]과 [1] 비교, [1]과 [2] 비교, [2]와 [3] 비교(이때 큰 값을 오른쪽에 위치시킴)
# 3단계 : [2, 1, 4, 6, 9] -> [0]과 [1] 비교, [1]과 [2] 비교(이때 큰 값을 오른쪽에 위치시킴)
# 4단계 : [1, 2, 4, 6, 9] -> [0]과 [1] 비교(이때 큰 값을 오른쪽에 위치시킴)
input = [4, 6, 2, 9, 1]
def bubble_sort(array):
n = len(array)
for i in range(n-1):
for j in range(n-i-1):
if array[j] > array[j+1]:
array[j], array[j+1] = array[j+1], array[j]
return array
bubble_sort(input)
print(input) # [1, 2, 4, 6, 9] 가 되어야 합니다!
print("정답 = [1, 2, 4, 6, 9] / 현재 풀이 값 = ",bubble_sort([4, 6, 2, 9, 1]))
print("정답 = [-1, 3, 9, 17] / 현재 풀이 값 = ",bubble_sort([3,-1,17,9]))
print("정답 = [-3, 32, 44, 56, 100] / 현재 풀이 값 = ",bubble_sort([100,56,-3,32,44]))
- 선택 정렬 : 가장 큰 값 또는 가장 작은 값을 선택해 가장 앞에 위치시키는 방법 -> O(n^2) 시간
# 1 단계 : [1, 6, 2, 9, 4] -> [0]과 [1] 비교, [1]과 [2] 비교, [2]와 [3] 비교 후 가장 작은 수 1과 [0] 위치에 있는 수 swap
# 2 단계 : [1, 2, 6, 9, 4] -> [1]과 [2] 비교, [2]와 [3] 비교 후 가장 작은 수 2와 [1] 위치에 있는 수 swap
# 3 단계 : [1, 2, 4, 9, 6] -> [2]와 [3] 비교 후 가장 작은 수 4와 [2] 위치에 있는 수 swap
# 4 단계 : [1, 2, 4, 6, 9] -> [3]와 [4] 비교 후 가장 작은 수 6와 [3] 위치에 있는 수 swap
input = [4, 6, 2, 9, 1]
def selection_sort(array):
n = len(array)
for i in range(n-1):
min_index = i
for j in range(n - i):
if array[i+j] < array[min_index]:
min_index = i+j
array[i], array[min_index] = array[min_index], array[i]
return array
selection_sort(input)
print(input) # [1, 2, 4, 6, 9] 가 되어야 합니다!
print("정답 = [1, 2, 4, 6, 9] / 현재 풀이 값 = ",selection_sort([4, 6, 2, 9, 1]))
print("정답 = [-1, 3, 9, 17] / 현재 풀이 값 = ",selection_sort([3,-1,17,9]))
print("정답 = [-3, 32, 44, 56, 100] / 현재 풀이 값 = ",selection_sort([100,56,-3,32,44]))
- 삽입 정렬 : 특정 원소를 정렬된 원소들 사이에 삽입하는 방법 -> O(n^2) 시간, but 최선은 n
# 원래 : [4, 6, 2, 9, 1]
# 1단계 : [4, 6, 2, 9, 1] -> [0]은 정렬된 것으로 보고, [1]을 [0]과 비교([0]보다 [1]의 값이 크기 때문에 그대로 둔다.)
# 2단계 : [2, 4, 6, 9, 1] -> [1]까지 정렬된 것으로 보고, [2]을 [1]과 비교해 값이 작으면 서로의 위치 변경, [1]을 [0]과 비교해 값이 작으면 서로 위치 변경
# 3단계 : [2, 4, 6, 9, 1] -> [2]까지 정렬된 것으로 보고, [3]을 [2]와 비교([2]보다 [3]의 값이 크기 때문에 그대로 둔다.)
# 4단계 : [1, 2, 4, 6, 9] -> [3]까지 정렬된 것으로 보고, [4]를 [3]과 비교해 값이 작으면 서로의 위치 변경, [3]를 [2]과 비교해 값이 작으면 서로의 위치 변경, [2]를 [1]과 비교해 값이 작으면 서로의 위치 변경, [1]를 [0]과 비교해 값이 작으면 서로의 위치 변경
input = [4, 6, 2, 9, 1]
def insertion_sort(array):
n = len(array)
for i in range(1, n):
for j in range(i):
if array[i-j-1] > array[i-j]:
array[i-j-1], array[i-j] = array[i-j], array[i-j-1]
else:
break
return array
insertion_sort(input)
print(input) # [1, 2, 4, 6, 9] 가 되어야 합니다!
print("정답 = [4, 5, 7, 7, 8] / 현재 풀이 값 = ",insertion_sort([5,8,4,7,7]))
print("정답 = [-1, 3, 9, 17] / 현재 풀이 값 = ",insertion_sort([3,-1,17,9]))
print("정답 = [-3, 32, 44, 56, 100] / 현재 풀이 값 = ",insertion_sort([100,56,-3,32,44]))
반응형
'개발일지 > AI 캠프' 카테고리의 다른 글
내일배움캠프 AI, 16일차 TIL - 2022.09.21 (0) | 2022.09.21 |
---|---|
내일배움캠프 AI, 15일차 TIL - 2022.09.20 (1) | 2022.09.21 |
내일배움캠프 AI - 3주차 WIL (0) | 2022.09.18 |
내일배움캠프 AI, 13일차 TIL - 2022.09.16 (0) | 2022.09.17 |
내일배움캠프 AI - 12일차 TIL, 2022.09.15 (0) | 2022.09.16 |