'K-Digital Training: 프로그래머스 인공지능 데브코스 2기' 첫 날.
그리고 배움기록 첫 날.
velog도 slack도 모든 것이 서툴고 어색하지만, 언제나 그랬듯 이또한 익숙해질 것이라 믿는다 :>
선형 배열(Linear Arrays)
python에는 서로 다른 종류의 데이터도 줄세울 수 있는 list 자료형이 있다.
.append(원소)
.pop()
.insert(인덱스, 원소)
.del(인덱스)
.index(원소)
: 가장 왼쪽에서 찾은 인덱스를 반환하므로 중복되는 원소가 있는 경우에 해당 원소의 모든 위치를 찾으려면 별도의 구현(슬라이싱 등)이 필요sorted()
: 내장 함수로, 정렬된 새로운 리스트 반환sort()
: 리스트의 메서드로, 해당 리스트가 정렬됨재귀 알고리즘(Recursive Algorithms)
같은 알고리즘을 반복적으로 적용하여 주어진 문제를 같은 종류의 보다 쉬운 문제의 답을 이용해 풀 수 있다. 재귀 호출의 종결 조건(trivial case)을 꼭 명시해야 한다.
재귀 알고리즘의 효율성 측면
- 재귀 알고리즘으로 풀 수 있는 문제는 순환문을 이용한 반복적(iterative) 알고리즘으로도 풀 수 있음
- 일반적으로 반복적 알고리즘이 재귀 알고리즘보다 문제 풀이의 시간적 효율이 높음
재귀적 방법으로 조합의 수 계산하기
- 특정 원소 입장에서 볼 때, 이 원소를 포함하는 경우의 수와 그렇지 않은 경우의 수를 따로 계산해서 더함
def combi(n, m):
if n == m:
return 1
elif m == 0:
return 1
else:
return combi(n - 1, m) + combi(n - 1, m - 1)
알고리즘의 시간 복잡도(Time Complexity)
알고리즘을 실행함에 있어 문제의 크기가 커짐에 따라서 얼마나 긴 시간을 요구하느냐를 뜻한다.
연결 리스트(Linked List)
"각 원소들을 줄줄이 엮어서" 관리하는 방식으로, 원소의 삽입/삭제를 빠른 시간 내에 처리할 수 있다.
배열 | 연결 리스트 | |
---|---|---|
저장 공간 | 연속한 위치 | 임의의 위치 |
특정 원소 지칭 | 매우 간편 O(1) | 선형 탐색과 유사 O(n) |
class Node:
def __init__(self, item):
self.data = item
self.next = None
class LinkedList:
def __init__(self):
self.nodeCount = 0
self.head = None
self.tail = None
def getAt(self, pos):
if pos < 1 or pos > self.nodeCount:
return None
i = 1
curr = self.head
while i < pos:
curr = curr.next
i += 1
return curr
def traverse(self):
answer = []
curr = self.head
while curr:
answer.append(curr.data)
curr = curr.next
return answer
def insertAt(self, pos, newNode):
if pos < 1 or pos > self.nodeCount + 1:
return False
# 맨 앞에 삽입하는 경우
if pos == 1:
newNode.next = self.head
self.head = newNode
else:
# 맨 뒤에 삽입하는 경우
if pos == self.nodeCount + 1:
prev = self.tail
# 중간에 삽입하는 경우
else:
prev = self.getAt(pos - 1)
newNode.next = prev.next
prev.next = newNode
if pos == self.nodeCount + 1:
self.tail = newNode
self.nodeCount += 1
return True
def popAt(self, pos):
if pos < 1 or pos > self.nodeCount:
raise IndexError
if self.nodeCount == 1:
curr = self.head
self.head = None
self.tail = None
self.nodeCount = 0
return curr.data
if pos == 1:
curr = self.head
self.head = self.head.next
else:
prev = self.getAt(pos - 1)
if pos == self.nodeCount:
curr = self.tail
prev.next = None
self.tail = prev
else:
curr = prev.next
prev.next = curr.next
self.nodeCount -= 1
return curr.data
def concat(self, L):
self.tail.next = L.head
# L이 빈 리스트인지 체크
if L.tail:
self.tail = L.tail
self.nodeCount += L.nodeCount
class Node:
def __init__(self, item):
self.data = item
self.next = None
class LinkedList:
def __init__(self):
self.nodeCount = 0
self.head = Node(None)
self.tail = None
self.head.next = self.tail
class Node:
def __init__(self, item):
self.data = item
self.prev = None
self.next = None
class DoublyLinkedList:
def __init__(self):
self.nodeCount = 0
self.head = Node(None)
self.tail = Node(None)
self.head.prev = None
self.head.next = self.tail
self.tail.prev = self.head
self.tail.next = None
스택(Stacks)
후입선출(LIFO: last-in-first-out) 자료 구조, 마지막에 넣은 것이 가장 먼저 꺼내어지는 위에 입구가 하나있는 박스를 생각하면 쉽다.
class ArrayStack:
def size(self):
return len(self.data)
def isEmpty(self):
return self.size == 0
def push(self, item):
self.data.append(item)
def pop(self):
return self.data.pop()
def peek(self):
return self.data[-1]
class LinkedListStack:
def __init__(self):
self.data = DoublyLinkedList()
def size(self):
return self.data.getLength()
def isEmpty(self):
return self.size() == 0
def push(self, item):
node = Node(item)
self.data.insertAt(self.size() + 1, node)
def pop(self):
return self.data.popAt(self.size())
def peek(self):
return self.data.getAt(self.size()).data
공부를 마치며
생각보다 학습량이 꽤 많다. 밀리지 않고 들어야 나중에 고생을 안하겠구나...😂