
자료구조 알고리즘 주차는 오늘이 마지막이고 내일부터는 C언어로 본격적으로 넘어가게 됩니다.
그래서 작별인사 느낌으로 지금까지 공부한 내용들을 한 글로 정리해보았습니다.
map으로 각 원소에 int 적용# `12345`와 같이 공백 없는 숫자 입력
a, b, c, d, e = map(int, input()) # 각각 변수로
nums = list(map(int, input())) # 리스트로
# `1 2 3 4 5`와 같이, 공백으로 구분된 숫자 입력
a, b, c, d, e = map(int, input().split()) # 각각 변수로
nums = list(map(int, input().split())) # 리스트로
sys.stdin.readline으로 빠르게 입력 받기\n을 포함하므로, 수동으로 없애줘야 함import sys
input = sys.stdin.readline
text = input().strip() # 맨 뒤 '\n'을 제거
num = int(input()) # int 등 함수는 자동 제거
sys.setrecursionlimit(최대깊이)로 최대 재귀 깊이를 늘려 스택 오버플로우 방지10 ** 3인데, 보통 10 ** 9 정도로 늘리면 문제없음import sys
sys.setrecursionlimit(10 ** 9)
# 유클리드 호제법
def gcd(x, y):
if y == 0: # 무조건 종료 조건을 둘 것
return x
else:
return gcd(y, x % y)
print(gcd(22, 8)) # 2
| N 크기 | 가능한 최대 시간 복잡도 | 예시 |
|---|---|---|
| 약 | 조합, 순열 등 | |
| 약 | 완전 탐색 등 | |
| 약 | 삼중 반복문 | |
| 약 | 이중 반복문 | |
| 약 ~ | 정렬 | |
| 약 ~ | 단일 반복문, 선형 탐색 | |
| 사실상 무한 | 이분 탐색 | |
| 무한 | 수학공식 등 신박한 풀이 |
[[0] * (열의 수) for _ in range(행의 수)]로 쉽게 만들 수 있음| 연산 | 코드 | 시간복잡도 |
|---|---|---|
| 인덱스로 원소 접근 | list[인덱스] | |
| 맨 뒤에 값을 삽입 | list.append(값) | |
| 맨 뒤의 값을 삭제 | list.pop() -> 매개변수 없으면 마지막 인덱스 삭제 | |
| 원소 수 확인 | len(list) | |
| 맨 앞 / 중간에 값을 삽입 | list.insert(인덱스, 값) | |
| 맨 앞 / 중간의 값 삭제 | list.pop(인덱스) | |
| 원소의 존재 여부 확인 | 값 (not) in list | |
| 슬라이싱 | list[a:b] | 는 슬라이싱된 원소 수 |
| 그 외... | list.index(값), list.count(값) |
deque) 쓸 것.deque.appendleft()로 추가, deque.popleft()로 삭제는 set) 쓸 것.in, not in 연산은 .sort(), sorted()의 시간 복잡도는 약 words = ['banana', 'melon', 'kiwi', 'pineapple', "grape"]
print(sorted(words))
# ['banana', 'grape', 'kiwi', 'melon', 'pineapple']
print(sorted(words, reverse=True)) # 내림차순 정렬
# ['pineapple', 'melon', 'kiwi', 'grape', 'banana']
print(sorted(words, key=lambda x: (len(x), x)))
# 길이 순 -> 길이가 같으면 사전 순으로 정렬
# ['kiwi', 'grape', 'melon', 'banana', 'pineapple']
itertools를 이용해 순열, 조합 계산 가능조합
(1, 2), (2, 1)은 같은 조합)from itertools import combinations
a = [1, 2, 3, 4]
# 리스트 a에서 원소 2개를 뽑은 조합을 튜플로 반환
for cmb in combinations(a, 2):
print(cmb, end=" ")
# (1, 2) (1, 3) (1, 4) (2, 3) (2, 4) (3, 4)
순열
(1, 2), (2, 1)은 다른 순열)from itertools import permutations
a = [1, 2, 3, 4]
# 리스트 a에서 원소 2개를 뽑은 순열을 튜플로 반환
for pm in permutations(a, 2):
print(pm, end=" ")
# (1, 2) (1, 3) (1, 4) (2, 1) (2, 3) (2, 4) (3, 1) (3, 2) (3, 4) (4, 1) (4, 2) (4, 3)

list.append()로 푸시, list.pop()으로 팝, list[-1]로 맨 위 원소 확인 가능stack = []
# 스택에 데이터 푸시: .append()
stack.append(33)
stack.append(9)
stack.append(41)
# 스택에서 데이터 팝: .pop()
# 빈 스택에서 팝할 시, IndexError 발생하니 유의할 것
print(stack.pop()) # 41
# 다시 데이터 푸시
stack.append(1)
stack.append(10)
# 스택의 마지막 값 확인
print(stack[-1]) # 10
# 스택의 크기 구하기
stack_size = len(stack) # 현재 스택은 [33, 9, 1, 10]
print(stack_size) # 4
# 다시 데이터 팝
print(stack.pop()) # 10

collections.deque(데크)로 구현deque.append()로 인큐, deque.popleft()로 디큐, deque[0]로 맨 앞 원소 확인 가능from collections import deque
queue = deque()
# 큐에 데이터 인큐: .append()
queue.append(33)
queue.append(9)
queue.append(41)
# 큐에서 데이터 디큐: .popleft()
print(queue.popleft()) # 33
# 다시 데이터 인큐
queue.append(1)
queue.append(10)
# 큐의 맨 앞 값 확인
print(queue[0]) # 9
# 큐의 크기 구하기
queue_size = len(queue) # 현재 큐는 [9, 41, 1, 10]
print(queue_size) # 4
# 다시 데이터 디큐
print(queue.popleft()) # 9
players = {51: "창기", 10: "지환", 1: "찬규"}a[51]): 에 근접a[8] = "성주"): 에 근접a.pop(10)): 에 근접dict는 삽입 순서를 유지하도록 구현됨for key in dict 등 사용 시, 정해진 순서대로 순회nums = {1, 2, 3}1 in a): 에 근접nums.add(4)): 에 근접nums.remove(3)): 에 근접for num in nums 등 사용 시 임의의 순서대로 순회됨Counter - 개수 세기from collections import Counter
a = Counter("123456654456")
print(a)
# Counter({'4': 3, '5': 3, '6': 3, '1': 1, '2': 1, '3': 1})
# 없는 키를 인덱싱할 시, KeyError 발생 X - 0을 리턴
print(a['4']) # 3
print(a['2']) # 1
print(a['0']) # 없는 키: 0
print(a['ㄹㅇㄹㅇㄹㅇ']) # 없는 키: 0
# 가장 많이 등장한 항목 순으로, (원소, 개수) 쌍 확인
print(a.most_common())
# [('4', 3), ('5', 3), ('6', 3), ('1', 1), ('2', 1), ('3', 1)]
print(a.most_common(2)) # 상위 2개만
# [('4', 3), ('5', 3)]
defaultdict - 기본값 부여KeyError 발생 Xdefaultdict(int)의 기본값은 0, defaultdict(list)의 기본값은 []defaultdict(lambda: '기본값')으로 원하는 기본값 설정 가능from collections import defaultdict
# 기본값이 0
count = defaultdict(int)
count["딸기"] += 1 # 기본값인 0에 1 더함
print(count) # defaultdict(<class 'int'>, {'딸기': 1})
# 기본값이 빈 리스트
songs = defaultdict(list)
songs["이찬혁"].append("이찬혁") # 기본값인 빈 리스트에 원소 삽입
songs["악뮤"].append("이수현")
print(songs) # defaultdict(<class 'list'>, {'악뮤': ['이찬혁', '이수현']})
# 사용자 정의 기본값
points = defaultdict(lambda: 50)
print(points["상록"]) # 기본값인 50 반환
print(points) # defaultdict(<function <lambda> at 0x00000201556E9760>, {'상록': 50})

왜 여기만 그래픽이 깔쌈하냐고요? 정글 책만들기 과제에서 제가 맡은 부분이 여기여서...
heapq 모듈 사용해, 리스트를 최소 힙처럼 사용 가능heapq.heappush(리스트, x)로 삽입 ()heapq.heappop(리스트)로 최솟값 꺼내기 ()리스트[0]으로 현재 루트 노드의 최솟값 확인 ()heapq.heapify(리스트)로 기존 리스트의 원소를 힙 조건을 만족하도록 재배치 가능 ()import heapq
heap = []
# 힙에 값 삽입
heapq.heappush(heap, 3)
heapq.heappush(heap, 1)
heapq.heappush(heap, 5)
# 현재 최솟값 확인 (루트노드)
print(heap[0]) # 1
# 힙에서 값 꺼내기
print(heapq.heappop(heap)) # 1
print(heapq.heappop(heap)) # 3
print(heapq.heappop(heap)) # 5
# 기존 리스트를 최소 힙으로 재구성
b = [9, 5, 2, 7]
heapq.heapify(b)
print(b[0]) # 2
print(heapq.heappop(b)) # 2
heapq는 최소 힙 기반이므로, 최대 힙처럼 사용할 땐 값을 음수 처리해 주어야 함
list.index(x) 메서드도 선형 탐색, 
# a에서 target 찾기
def binary_search(a, target):
l = 0 # 검색 범위 맨 앞의 인덱스
r = len(a) - 1 # 검색 범위 맨 끝의 인덱스
while True:
m = (l + r) // 2 # 중앙 원소의 인덱스
if a[m] == target: # target을 찾은 경우
return m
elif a[m] < target: # 인덱스 m 이후에 target 존재
l = m + 1
else:
r = m - 1
if l > r: # 더 이상 검색할 값이 없음
return -1 # 찾지 못한 경우 -1 반환
print()

상록님 믿고 이제 공부 안 할게요