map
- "정수"형태의 입력값 A,B를 한번에 받는다.
- 위의 변수명 A,B처럼 여러개의 변수명을 선언할 필요 없이 한번에 입력받기가 가능
index
a = list.index(b)
- 리스트안에서의 b의 위치를 인덱스값으로 반환
- 인덱스값은 0부터 시작하기 때문에 1부터 시작하고 싶다면 출력할때 a+1로 하면됨
set
list(set(list))
- 순서를 신경 쓸 필요 없을경우 유용
- 리스트 내부의 중복되는 값을 제거함
sys.stdin.readline()
- "입력 속도를 비약적으로 높여주는 도구"
- 보통 input() 대신 sys.stdin.readline()을 사용함
사용 이유
- input()
- 사용 편의성을 위해 여러 가지 내부 처리를 거침
- 입력받은 값의 끝에 있는 줄바꿈 문자(\n)를 자동으로 제거
- input("입력하세요: ")처럼 안내 문구를 출력할 수 있는 기능이 있어 추가적인 부하가 발생
- sys.stdin.readline()
- 데이터를 한 번에 뭉텅이(버퍼)로 읽어오는 방식(대량의 데이터를 읽을 때 훨씬 빠름)
비교
- 입력데이터가 10만개 100만개 등등 비약적으로 많아질 경우
- input()을 쓰면 '시간 초과(Time Limit Exceeded)'가 날 확률이 매우 높음
- sys.stdin.readline()을 쓰면 가볍게 통과하는 경우가 많음
사용 시기
- 입력 개수가 10,000개 이상인 문제
- 반복문 안에서 input()을 호출해야 할 때
- 일반적인 문제
- 습관적으로 써두면 시간 초과 걱정을 덜 수 있어 좋음
주의
- sys.stdin.readline()은 문장의 끝에 있는 줄바꿈 문자(\n)까지 통째로 읽어옴
- 예를 들어 hello라고 치면 "hello\n"이 저장됨
- 문자열을 다룰 때는 반드시
.rstrip() 을 붙여서 공백을 제거해주는 것이 좋음
사용법
import sys
data = sys.stdin.readline()
n = int(sys.stdin.readline())
a, b, c = map(int, sys.stdin.readline().split())
팁
- sys.stdin.readline()을 길게 치는 건 번거로움
import sys
input = sys.stdin.readline
n = int(input())
정렬
sort() 메소드 (제자리 정렬)
- 리스트 자체를 직접 수정하여 정렬합니다.
- 원본 리스트를 유지할 필요가 없을 때 사용하며, 메모리를 아낄 수 있습니다.
nums = [5, 2, 9, 1, 5]
nums.sort()
print(nums)
words = ["banana", "apple", "cherry", "Apple"]
words.sort()
print(words)
sorted() 함수 (새로운 리스트 반환)
- 원본 리스트는 그대로 두고, 정렬된 새로운 리스트를 만들어 반환합니다.
- 원본 데이터가 나중에 필요할 때 유용합니다
nums = [5, 2, 9, 1, 5]
new_nums = sorted(nums)
print(new_nums)
print(nums)
사용자 정의 정렬(key 활용)
- key 파라미터에 함수를 전달하면, 그 함수의 결과값을 기준으로 정렬을 수행
단일 기준 정렬 (예: 문자열 길이순)
words = ["apple", "it", "banana", "kiwi"]
words.sort(key=len)
print(words)
다중 기준 정렬 (lambda 활용)
- "먼저 길이순으로 정렬하고,
- 길이가 같다면 알파벳 순으로 정렬해줘"와 같은 복합 조건이 필요할 때 lambda를 사용
members = [(25, "John"), (20, "Alice"), (25, "Bob"), (20, "David")]
members.sort(key=lambda x: (x[0], x[1]))
print(members)
-
words = ["apple", "bat", "banana", "art", "kiwi", "ace"]
words.sort(key=lambda x: (len(x), x))
print(words)
-
words = ["apple", "bat", "banana", "art", "kiwi", "ace"]
words.sort(key=lambda x: (-len(x), x))
print(words)
sorted

numbers = [10, 1, 5, 8, 2]
print(sorted(numbers))
print(sorted(numbers, reverse=True))
data = {'apple': 3, 'banana': 1, 'cherry': 2}
print(sorted(data))
print(sorted(data.items(), key=lambda x: x[1]))
text = "python"
print(sorted(text))
n = 5291
sorted_n = int("".join(sorted(str(n))))
print(sorted_n)
유용한 정렬 옵션
- reverse=True: 내림차순 정렬이 필요할 때 사용합니다.
- key 파라미터: 정렬 기준을 직접 정할 때 사용합니다.
words = ['banana', 'pie', 'apple', 'kiwi']
short_words = sorted(words, key=len)
print(short_words)
N = int(input())
S = int("".join(sorted(str(N),reverse=True)))
print(S)
set
A = ['a', 'a', 'b', 'b', 'c', 'c', 'c', 'd']
B = list(set(A))
print(B)
ceil
리스트 안의 내용물만 공백으로 구분해서 출력
join 메서드 사용
- 리스트의 요소가 문자열(str)일 때 사용할 수 있는 가장 세련된 방법
- 리스트 안에 숫자(int)가 들어있다면, 먼저 문자열로 변환하는 과정이 필요
arr = ['1', '2', '3', '4']
print(" ".join(arr))
nums = [1, 2, 3, 4]
print(" ".join(map(str, nums)))
Unpacking 연산자 (*) 사용
- print 함수에 리스트를 넘길 때 앞에
*를 붙이면, 리스트의 요소를 하나씩 낱개로 풀어서 전달
- 별도의 변환(map) 과정 없이 숫자 리스트도 바로 출력 가능
nums = [1, 2, 3, 4]
print(*nums)
반복문과 end 파라미터 사용
- 복잡한 조건이 필요하거나 알고리즘의 흐름을 직접 제어하고 싶을 때 사용
- print 함수는 출력 후 기본적으로 줄바꿈을 하지만, end 옵션을 주면 줄바꿈 대신 다른 문자를 넣을 수 있음
- 단점: 마지막 숫자 뒤에도 공백이 하나 더 붙게됨
nums = [1, 2, 3, 4]
for x in nums:
print(x, end=" ")
Counter
collections.Counter 는 파이썬에서 "항목의 개수를 세는 기계"
- 리스트나 문자열 같은 반복 가능한(iterable) 객체를 넣으면,
- 각 요소가 몇 번 등장했는지 세어서 딕셔너리 형태로 반환해 줌
Counter의 기본 작동 원리
from collections import Counter
my_list = ['apple', 'blue', 'apple', 'red', 'red', 'apple']
count_result = Counter(my_list)
print(count_result)
print(count_result['apple'])
print(count_result['grape'])
성능
- list.count()와 Counter를 비교
- list.count(x)
- 리스트를 처음부터 끝까지 다 훑으면서 x가 몇 개인지 찾습니다.
- 리스트 길이를 N, 찾는 횟수를 M이라 하면 전체 시간 복잡도는
O(N X M)
- Counter(list)
- 리스트를 단 한 번만 훑으면서
(O(N)) 모든 요소의 개수를 세어 딕셔너리에 저장합니다.
- 그 후 개수를 찾는 건 딕셔너리 조회
(O(1))이므로, 전체 시간 복잡도는 O(N + M)
유용한 기능
- most_common(n)
- 가장 많이 등장한 상위 n개의 요소를 리스트 안의 튜플 형태로 반환합니다.
c = Counter('abracadabra')
print(c.most_common(2))
- Counter끼리는 더하기, 빼기, 교집합, 합집합 연산이 가능
c1 = Counter(a=3, b=1)
c2 = Counter(a=1, b=2)
print(c1 + c2)
print(c1 - c2)
sys.stdin.read
- input()이나 sys.stdin.readline()은 한 줄씩 읽어오지만
- sys.stdin.read()는 입력값 전체를 하나의 거대한 문자열로 통째로 읽어옴
사용 예시
# 입력 데이터
3 4
ohhenrie
charlie
baesangwook
obama
baesangwook
ohhenrie
clinton
- sys.stdin.read() 실행 직후
- "3 4\nohhenrie\ncharlie\nbaesangwook\nobama\nbaesangwook\nohhenrie\nclinton"
- .split() 실행 직후
- 공백이나 줄바꿈을 기준으로 문자열을 쪼개서 하나의 리스트로 만듬
['3', '4', 'ohhenrie', 'charlie', 'baesangwook', 'obama', 'baesangwook', 'ohhenrie', 'clinton']
.split()
- .split() 함수는 인자(괄호 안)를 비워두면
- 스페이스(공백), 탭(\t), 엔터(줄바꿈, \n)를 모두 똑같은 '나누는 기준'으로 봄
3 4 ohhenrie charlie baesangwook ...
3 4
ohhenrie
charlie
baesangwook
...
['3', '4', 'ohhenrie', 'charlie', 'baesangwook', ...]
종료
- input()은 엔터를 치면 즉시 다음 코드로 넘어가지만
- sys.stdin.read()는 "이제 입력이 진짜 끝났다(EOF)"라는 신호를 줄 때까지 계속 기다림
집합(set) 연산자
& (교집합 연산)
- set(집합) 자료구조에 사용하는 & 연산자는 수학의 '교집합'과 똑같은 역할
- 즉, "두 곳에 모두 포함된 데이터만 골라내기"를 수행
A = {"철수", "영희", "길동"}
B = {"영희", "길동", "민수"}
result = A & B
print(result)
| (합집합 연산)
- 두 집합의 모든 원소를 합칩니다. (중복된 값은 알아서 하나만 남깁니다.)
A = {"철수", "영희", "길동"}
B = {"길동", "민수", "희수"}
result = A | B
- (차집합)
- 앞의 집합에서 뒤의 집합과 겹치는 원소를 빼버립니다.
A = {"철수", "영희", "길동"}
B = {"길동", "민수", "희수"}
result = A - B
^ (대칭 차집합)
- 둘 중 한 곳에만 속한 원소들을 합칩니다. (즉, 공통된 부분만 쏙 뺍니다.)
A = {"철수", "영희", "길동"}
B = {"길동", "민수", "희수"}
result = A ^ B
출력 최적화
- 출력해야 할 명단이 수십만 개라면
- for문 안에서 print()를 반복하는 것보다 문자열을 하나로 합쳐서 한 번에 출력하는 것이 더 빠를 수 있음
'\n'.join(result)
- 리스트의 모든 요소를 줄바꿈 문자(\n)로 연결해 하나의 거대한 문자열로 만든 뒤 한 번에 출력하는 기법
for name in result:
print(name)
print('\n'.join(result))
이항계수
이론
- 주어진 집합에서 순서에 상관없이 원소를 선택하는 방법의 가짓수를 의미
공식

문제 분석 및 접근 방식
n과 k가 작은 경우 (n <= 30)
n이 적당히 큰 경우 (n <= 1000)
- O(n^2)의 시간 복잡도를 가지는 동적 계획법을 사용
n이 매우 크고 소수 M으로 나눈 나머지를 구할 때
- 페르마의 소정리를 이용한 O(n) 풀이가 필요
if __name__ == '__main__':
- 이 문장은 파이썬 파일이 직접 실행되었을 때만 특정 코드를 동작시키게 만드는 '안전장치'
def solve_dp():
...
if __name__ == '__main__':
solve_dp()
직접 실행할 때 (주인공)
- 우리가 파이썬 파일을 직접 실행하면 파이썬은 이 파일의 이름을
__main__이라고 인식
- 그래서 조건문이 참(True)이 되어 solve_apart()가 실행
다른 파일에서 불러올 때 (조연)
- 만약 다른 파일에서
import my_code 처럼 이 파일을 부품으로 가져다 쓴다면,
- 이름이
__main__이 아니라 파일명으로 인식됨
- 이때는 조건문이 거짓(False)이 되어 내부 코드가 멋대로 실행되지 않음