시간 복잡도(time complexity)
알고리즘의 성능을 나타내는 지표로, 입력 크기에 대한 연산 횟수의 상한을 의미합니다.
시간 복잡도는 낮으면 낮을수록 좋습니다.
입력 크기에 따른 연산 횟수의 추이를 활용해서 시간 복잡도를 표현하는 방법을 점근적 표기법이라고 합니다.
코딩 테스트 필수 문법
빌트인 데이터 타입(built-in data type)은 언어 자체에서 제공하는 데이터 타입과 컬렉션 데이터 타입이 있습니다.
- 기본 데이터 타입: int, float, string
- 컬렉션 데이터 타입: list, tuple, set, dictionary
정수형 비트 연산
print(a & b) # AND / 4
print(a | b) # OR / 13
print(a ^ b) # XOR / 9
print(~a) # NOT / -14
print(a << 2) # 왼쪽 시프트 (a에 2^2를 곱한 것과 동일) / 52
print(a >> 1) # 오른쪽 시프트 (a를 2^1로 나눈 것과 동일) / 6
엡실론을 포함한 연산에 주의하라
부동소수형 코드 실행 결과를 보면 눈에 띄는 내용이 있습니다.
10% 3.2의 연산 결과를 보면 결괏값이 0.4가 아니라 0.39999999947입니다.
이런 이유는 파이썬은 부동소수형 데이터를 이진법으로 표현하기 때문입니다.
표현 과정에서 오차가 발생하는 것이죠.
이를 엡실론(epsilon)이라고 합니다.
부동소수형 데이터를 활용하는 문제는 오차 허용 범위를 언급하는 경우가 많습니다.
문제를 분석할 때 꼭 이 부분을 체크하기 바랍니다. 이 지점에서 정말 많은 사람이 실수 합니다.
컬렉션 데이터 타입
컬렉션은 여러 값을 담는 데이터 타입을 말합니다.
list, tuple, dictionary, set, stirng 등이 있습니다.
- 변경할 수 있는 객체(mutable object)
- list, dictionary, set
- 변경할 수 없는 객체(immutable object)
- int, float, string, tuple
a = 4 # ➊ a = 4
b = a # ➋ a = 4, b = 4 / b는 a가 아닌 a가 참조한 4를 참조
b += 2 # ➌ b = 6 / 기존에 참조한 객체를 수정하지 않음, 새 객체 6을 참조
print(a, b) # 4 6
➌에 의해 b는 6이라는 객체를 참조합니다. 주목할 점은 4는 이뮤터블 객체이므로 수정할 수 없습니다.
따라서 객체 6을 새로 생성하고 그 객체를 참조합니다.
딕셔너리
파이썬의 딕셔너리는 key와 value 쌍을 저장하는 해시 테이블로 구현되어 있습니다.
이름 그대로 키를 사용하여 값을 검색하는 자료형이라고 생각하면 됩니다.
튜플
튜플은 이뮤터블 객체입니다.
리스트, 딕셔너리와 달리 한 번 생성하면 삽입하거나 삭제할 수 없습니다.
튜플은 삽입, 삭제는 되지 않지만 인덱싱, 슬라이싱은 할 수 있습니다.
my_tuple = (1, 2, 3)
# 인덱싱
print(my_tuple[0]) # 1
print(my_tuple[1]) # 2
print(my_tuple[2]) # 3
# 슬라이싱
print(my_tuple[1:]) # (2, 3)
print(my_tuple[:2]) # (1, 2)
print(my_tuple[1:2]) # (2,)
문자열
문자열은 문자들을 집합의 형태로 구성한 이뮤터블 객체입니다.
문자열은 이뮤터블 객체이므로 기존 객체를 수정하는 것이 아니라 새로운 객체를 반환합니다.
문자열 수정
문자열을 수정하고 싶다면 replace() 메서드를 사용하면 됩니다.
replace() 메서드는 첫 번째 인수에 찾을 문자열을, 두 번째 인수에 변경할 문자열을 넣어 사용합니다.
함수 호출
함수를 정의했으면 함수를 호출할 수 있습니다.
함수를 호출할 때 매개변수가 있는 경우 func(a,b)와 같이 인수를 함께 전달합니다.
* 매개변수와 인수의 차이
매개변수(parameter)란 함수의 정의에서 전달받은 인수를 함수 내부로 전달하기 위해 사용하는 변수
인수(argument)란 함수가 호출될 때 함수로 값을 전달해주는 값
람다식
lambda x, y : x + y # x와 y를 받아서 더한 값을 반환하는 람다식
람다식은 2가지 패턴으로 자주 사용합니다.
- 변수로 참조
# 람다를 이용한 간단한 함수 정의
add = lambda x, y: x + y
print(add(5, 4)) # 9
- 인수로 넘기는 방식
num = [1, 2, 3, 4, 5] # ➊ 리스트 선언
squares = list(map(lambda x: x**2, num)) # ➋ 람다식 넘기기
print(squares) # [1, 4, 9, 16, 25]
람다식 활용 예제
1. map 함수와 함께 사용
map(함수, 리스트)
mylist = [1, 2, 3, 4, 5]
mylist2 = list(map(lambda x:x*2, mylist)) # [2, 4, 6, 8, 10]
2. filter 함수와 함께 사용
filter(함수, 리스트)
mylist = [1, 2, 3, 4, 5]
mylist2 = list(filter(lambda x:x%2==1, mylist)) # [1, 3, 5]
mylist2 = list(filter(lambda x:x<3, mylist)) # [1, 2]
3. sorted 함수와 함께 사용 (dictionary sorted())
mydict = {'e':5, 'b':6, 'a':2, 'd':7, 'c':1}
mydict2 = sorted(mydict.items(), key=lambda x: x[0])
# [('a',2), ('b',6), ('c',1), ('d',7), ('e',5)]
4. reduce 함수와 함께 사용
reduce(함수, 시퀀스)
from functools import reduce
reduce(lambda x,y: x+y, [0, 1, 2, 3, 4]) # 10
코딩 테스트 코드 구현 노하우
조기 반환(early return)
조기 반환은 코드 실행 과정이 함수 끝까지 도달하기 전에 반환하는 기법입니다.
이 방식은 코드의 가독성을 높여주고 예외를 조금 더 깔끔하고 빠르게 처리할 수 있습니다.
def total_price(quantity, price):
total = quantity * price # ➊
if total > 100: # ➋ total이 100보다 크면
return total * 0.9 # ➌ 조기 반환
return total
print(total_price(4, 50))
보호 구문(guard clauses)
보호 구문은 본격적인 로직을 진행하기 전 예외 처리 코드를 추가하는 기법입니다.
예를 들어 조건문을 이용하여 초기에 입력값이 유효한지 검사하고
그렇지 않으면 바로 함수를 종료하는 보호 구문을 쓸 수 있습니다.
def calculate_average(numbers):
if numbers is None: # ➊ 값이 없으면 종료(예외)
return None
if not isinstance(numbers, list): # ➋ numbers가 리스트가 아니면 종료(예외)
return None
if len(numbers) == 0: # ➌ numbers의 길이가 0이면 종료(예외)
return None
total = sum(numbers) # ➍
average = total / len(numbers)
return average
합성 함수(composite method)
합성 함수는 2개 이상의 함수를 활용하여 함수를 추가로 만드는 기법입니다.
보통 합성 함수는 람다식을 활용합니다.
def add_three(x): # ➊
return x + 3
def square(x): # ➋
return x * x
composed_function = lambda x: square(add_three(x)) # ➌
print(composed_function(3)) # ➍ (3 + 3)^2 = 36
'자료구조 및 알고리즘 > 코딩테스트 준비' 카테고리의 다른 글
코딩 테스트 완전 정복 ・ 스택 (0) | 2024.06.14 |
---|---|
코딩 테스트 완전 정복 ・ 배열 (0) | 2024.06.14 |
다이나믹 프로그래밍 (0) | 2024.06.12 |
정렬 ・ 이진 탐색 (0) | 2024.06.12 |
주요 라이브러리 ・DFS ・BFS (0) | 2024.06.12 |