내배캠 2022.11.14 (알고리즘 2주차)
04. 링크드 리스트 구현 -1
링크드 리스트 모든 원소 출력
링크드 리스트 원소 찾기/추가
링크드 리스트의 노드에는 들어간 값과 다음 연결된 노드가 무엇인지 (포인터)에 대해 속성을 넣어준다.
Node class 생성
class Node:
def __init__(self, data):
self.data = data
self.next = None
box_1 = Node(3)
box_2 = Node(4)
box_1.next = box_2
print(box_1)
print(box_1.data)
print(box_1.next)
print(box_1.next.data)
클래스를 만들면 노드에 정보를 넣는일을 일일이 반복하지 않아도 된다.
단순 반복을 줄여주는 링크드 리스트 클래스를 만들어보자
꼭 가지고 있어야할 정보는 맨 앞칸 정보이다. head node 만 가지고 있다.
그 외에는 옆으로 옆으로 넘어가면서 확인할 수 있기 때문이다.
1) linkedlist는 self.head에 시작하는 노드를 저장한다
2) 다음 노드를 보기위해서는 각 노드의 next를 조회해서 찾아간다.
줄 옮기기 단축기 ctrl + shif + 방향
링크드 리스트 class 생성
1. 위에 생성된 클래스 Node로 객체 속성을 data 와 next를 만들어준다.
2. 그 노드를 다시 클래스 linkedlist로 head라는 객체속성을 만든다.
프린트 해보면 linked 클랙스 객체속성 안에 Node 객체 속성이 들어있고 그것 안에 데이터가 있다는 것을 확인해볼 수있다.
append 메소드 링크드 리스트 클래스에 만들기
return은 함수가 종료되었다는 의미, 함수내의 변수나 어떤 값을 돌려주는 역할을 한다.
해당함수를 정상적으로 끝내고 운영체제에 값을 반환하고 현재 실행중이 해당함수를 벗어나겠다는 뜻
메소드 1. 새로운 노드를 만드는 append
메소드 2. 모든 노드들을 프린트해주는 print_all
링크드 리스트 원소 찾기 / 원소 추가/원소 삭제하기
index가 0일 경우에 index가 -1이 되버리는데 그 때는 어떻게 해야하나?
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
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 print_all(self):
cur = self.head
while cur is not None:
print(cur.data)
cur = cur.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)
if index == 0:
new_node.next = self.head
self.head = new_node
return
node = self.get_node(index -1)
next_node = node.next
node.next = new_node
new_node.next = next_node
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
linked_list = LinkedList(5)
linked_list.append(12)
linked_list.add_node(0,3)
linked_list.delete_node(1)
linked_list.print_all()
06. 링크드 리스트 문제
9) ✍️ 두 링크드 리스트의 합 계산
에러가 났을 때 파란색으로 나온 줄을 선택하면 에러가 난 줄로 갈 수 있다.
클래스 내부 함수를 이용할 때
self.함수명() 을 쓰면 된다.
def get_linked_list_sum(linked_list_1, linked_list_2):
sum_1 = 0
head_1 = linked_list_1.head
while head_1 is not None:
sum_1 = sum_1*10 + head_1.data
head_1 = head_1.next
sum_2 = 0
head_2 = linked_list_2.head
while head_2 is not None:
sum_2 = sum_2 * 10 + head_2.data
head_2 = head_2.next
return sum_1 + sum_2
그런데 여기서 1,2 숫자만 바뀐다. 반복되는 부분을 최소하기 위해서 아래와 같은 코드로 써주었다.
def get_linked_list_sum(linked_list_1, linked_list_2):
sum_1 = _get_linked_list_sum(linked_list_1)
sum_2 = _get_linked_list_sum(linked_list_2)
return sum_1 + sum_2
def _get_linked_list_sum(linked_list):
sum = 0
head = linked_list.head
while head is not None:
sum = sum*10 + head.data
head = head.next
근데 sum이라는 이름이 별로 좋은 이름이 아님 (내장함수에도 있어서 그런듯)
아래는 다른이름으로 바꿔주었다.
def get_linked_list_sum(linked_list_1, linked_list_2):
linked_list_sum_1 = _get_linked_list_sum(linked_list_1)
linked_list_sum_2 = _get_linked_list_sum(linked_list_2)
return linked_list_sum_1 + linked_list_sum_2
def _get_linked_list_sum(linked_list):
linked_list_sum = 0
head = linked_list.head
while head is not None:
linked_list_sum = linked_list_sum * 10 + head.data
head = head.next
return linked_list_sum
07. 이진 탐색
이진 탐색 binary search vs 순차 탐색 sequential search
이진 탐색은 중간을 숫자를 찍어서 업 다운 해가면서 목표 숫자찾기
순차 탐색은 처음부터 하나하나 비교해가면서 찾기
순차탐색 코드
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_sequential(target, array):
for number in array:
if target == number:
return True
return False
result = is_existing_target_number_sequential(finding_target, finding_numbers)
print(result) # True
이진탐색 코드
// 연산자를 이용하면 소수점 이하의 수를 모두 버리고 몫만 나타낼 수 있습니다.
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)
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 = array[current_guess] + 1
else:
current_max = array[current_guess] -1
current_guess = (current_min + current_max) //2
return False
result = is_existing_target_number_binary(finding_target, finding_numbers)
print(result)
순차탐색과 이분탐색의 시간 복잡도 비교
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_sequential(target, array):
for number in array: # 배열 길이 N만큼 연산
if target == number: 비교 1
return True
return False
result = is_existing_target_number_sequential(finding_target, finding_numbers)
print(result) # True
O(N)을 가진다.
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 대입 1
current_max = len(array) 대입 1
current_guess = (current_min + current_max) // 2 대입 1
while current_min <= current_max: 비교 1
if array[current_guess] == target: 비교 1
return True
elif array[current_guess] < target: 비교 1
current_min = array[current_guess] + 1 대입 1
else:
current_max = array[current_guess] -1 대입 1
current_guess = (current_min + current_max) //2 대입 1
return False
result = is_existing_target_number_binary(finding_target, finding_numbers)
print(result)
O(상수)
N/2k= 1
N = 2k
k = log2 N
O(logN) 아래의 조그만 2는 상수라서 의미 없기 때문에 이렇게만 표기한다.
티스토리 html 모드에 들어가서
<sup></sup> - 윗첨자
<sub></sub> - 아랫 첨자
무작위 수 찾기
Q. 다음과 같이 숫자로 이루어진 배열이 있을 때, 2이 존재한다면 True 존재하지 않는다면 False 를 반환하시오.
이 문제를 통해 이진 탐색의 전제 조건은 순서대로 배열 되어 있을 때라는 것을 깨달았다.
finding_target = 2
finding_numbers = [0, 3, 5, 6, 1, 2, 4]
sorting_numbers = sorted(finding_numbers)
def is_exist_target_number_binary(target, array):
current_min = 0
current_max = len(array)
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 = array[current_guess] + 1
else:
current_max = array[current_guess] - 1
current_guess = (current_min + current_max) // 2
return False
result = is_exist_target_number_binary(finding_target, sorting_numbers)
print(result)
08. 재귀 함수 - 1
재귀란? recursion
어떠한 것을 정의할 때 자기 자신을 호출하는
Q. 60에서 0까지 숫자를 출력하시오.
근데 무한 루프에 빠지면 recursion error 이라고 띄워주면서 파이썬에서 자동으로 멈춰준다.
def count_down(number):
if number > 0:
print(number) # number를 출력하고
count_down(number - 1) # count_down 함수를 number - 1 인자를 주고 다시 호출한다!
count_down(60)
count_ down 안에 count_down 들어있는 걸 볼 수 있다.
09. 재귀 함수 - 2
팩토리얼
3! 3*2*1
4! = 4 * 3!
factorial(n) = n* Factorial(n-1)
def count_down(number):
if number < 0:
return
print(number) # number를 출력하고
count_down(number - 1) # count_down 함수를 number - 1 인자를 주고 다시 호출한다!
count_down(60)
함수 안에 자기 자신을 이용하는 것
일반 반복문 썻던 답
def factorial(n):
total = 1
while n > 0:
total = total * n
n -= 1
return total
print(factorial(6))
재귀함수 이용한 답
def factorial(n):
if n == 1:
return 1
return n * factorial(n - 1)
print(factorial(6))
회문 검사
일반 반복문으로 쓴 코드
input = "abcba"
def is_palindrome(string):
n = len(string)
for i in range(n):
if string[i] != string[n - 1 - i]:
return False
return True
print(is_palindrome(input))
재귀함수를 이용한 코드
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))
재귀함수는 반복되는 것이 있고 줄어든다는 특징이 있다.
티스토리 임시저장 기능 좀 거지 같다... 어제만 해도 3번은 날려먹은듯
한번 발행하고 나서는 임시저장 안되는것도 불편
임시저장한걸 불러오는게 자동으로 되는거 말고, 그냥 내가 선택해서 임시저장 불러오기가 있었으면 좋겠는데
자꾸 빈 화면 자동으로 불러오고 내가 임시저장한건 날라가있다. 네이버에서는 됐었던 것 같은데
10. 2주차 끝 & 숙제 설명
Q1. 링크드 리스트 끝에서 K 번째 값 출력하기
Q. 링크드 리스트의 끝에서 K번째 값을 반환하시오.
Q2. 배달의 민족 배달 가능 여부
Q. 배달의 민족 서버 개발자로 입사했다. 상점에서 현재 가능한 메뉴가 ["떡볶이", "만두", "오뎅", "사이다", "콜라"] 일 때, 유저가 ["오뎅", "콜라", "만두"] 를 주문했다. 그렇다면, 현재 주문 가능한 상태인지 여부를 반환하시오.
Q3. ✍️ 더하거나 빼거나
Q. 음이 아닌 정수들로 이루어진 배열이 있다. 이 수를 적절히 더하거나 빼서 특정한 숫자를 만들려고 한다. 예를 들어 [1, 1, 1, 1, 1]로 숫자 3을 만들기 위해서는 다음 다섯 방법을 쓸 수 있다.
-1+1+1+1+1 = 3
+1-1+1+1+1 = 3
+1+1-1+1+1 = 3
+1+1+1-1+1 = 3
+1+1+1+1-1 = 3
사용할 수 있는 숫자가 담긴 배열 numbers, 타겟 넘버 target_number이 매개변수로 주어질 때 숫자를 적절히 더하고 빼서 타겟 넘버를 만드는 방법의 수를 반환하시오.