좋아!
지금부터 파이썬의 itertools 모듈을 이용해서 백트래킹(완전탐색) 문제를 푸는 방법을
실제 정보처리기사 실기나 코딩테스트에서 나올 법한 예제로 완전 해부해줄게.
1~4 사이 숫자 중에서 3개를 뽑아 나열한 모든 순열 출력하기
(단, 같은 숫자는 한 번만 사용할 수 있음)
[1, 2, 3, 4](1, 2, 3)
(1, 2, 4)
(1, 3, 2)
...
itertools.permutations() 사용from itertools import permutations
data = [1, 2, 3, 4]
for case in permutations(data, 3):
print(case)
permutations(data, 3)data에서 3개를 뽑아 순서 있게 나열하는 모든 경우를 반환| 순번 | case 값 (튜플) |
|---|---|
| 1 | (1, 2, 3) |
| 2 | (1, 2, 4) |
| 3 | (1, 3, 2) |
| … | … |
| 24 | (4, 3, 2) |
📌 총 결과: 4P3 = 4 × 3 × 2 = 24개 조합
itertools.permutations(), combinations() 등을 쓰면 그 자체가 완전탐색 결과를 만들어줌1~5 중에서 숫자 3개를 골라서 (순서 상관없이) 출력
from itertools import combinations
for comb in combinations([1, 2, 3, 4, 5], 3):
print(comb)
📌 이건 5C3 = 10개의 조합
1~4 중 3개를 골라 만들었을 때 합이 6인 경우만 출력
from itertools import permutations
data = [1, 2, 3, 4]
for case in permutations(data, 3):
if sum(case) == 6:
print(case)
✅ 조건을 걸면 → 백트래킹의 가지치기(pruning)과 유사한 효과
| 함수 | 의미 | 예시 |
|---|---|---|
permutations(data, r) | 순서 O, 중복 X | 4P3 |
combinations(data, r) | 순서 X, 중복 X | 5C3 |
product(data, repeat=r) | 순서 O, 중복 O | 중복 순열 |
combinations_with_replacement(data, r) | 순서 X, 중복 O | 중복 조합 |
def backtrack(path, used):
if len(path) == 3:
print(path)
return
for i in range(4):
if not used[i]:
used[i] = True
backtrack(path + [data[i]], used)
used[i] = False
data = [1, 2, 3, 4]
used = [False]*4
backtrack([], used)
✅ 이건 재귀 백트래킹
→ 같은 결과를 itertools.permutations()으로도 쉽게 얻을 수 있음
| 방식 | 장점 | 단점 |
|---|---|---|
itertools 사용 | 간단하고 빠름 | 복잡한 조건엔 비효율적 |
| 재귀 백트래킹 | 유연한 조건 처리 가능 | 코드 복잡함 |
좋아! 너가 딱 잘 짚었어.
아래 코드를 줄마다 **"이 줄에서 지금 무슨 일이 벌어지고 있는가?"**를 기준으로
완전 초보자 기준에서 1줄도 빠짐없이 해부해줄게.
그리고 실제로 값이 어떻게 만들어지는지도 하나하나 시각화해서 설명해줄게.
from itertools import permutations
data = [1, 2, 3, 4]
for case in permutations(data, 3):
print(case)
from itertools import permutationsitertools 중에서 permutations 함수만 가져온다permutations는 기본 내장 함수가 아니라 itertools 안에 있음 → 사용하려면 먼저 import 해야 함permutations를 쓸 수 있도록 가져와서 준비함data = [1, 2, 3, 4]1, 2, 3, 4data로 저장data = [1, 2, 3, 4]
for case in permutations(data, 3):이 줄이 가장 중요하니까 완전 자세히 쪼개서 설명할게.
permutations(data, 3)data = [1, 2, 3, 4] 에서
3개를 뽑아 만들 수 있는 순열:
(1, 2, 3)
(1, 2, 4)
(1, 3, 2)
(1, 3, 4)
(1, 4, 2)
(1, 4, 3)
(2, 1, 3)
(2, 1, 4)
...
(4, 3, 2)
➡ 총 24개 (4P3 = 4 × 3 × 2 = 24)
for case in permutations(data, 3):
이건 아래와 같이 동작해:
permutations(data, 3)
→ [(1,2,3), (1,2,4), (1,3,2), ..., (4,3,2)] ← 이터레이터(반복 가능한 값들)를 반환
for case in ...:
print(case)
→ 이 순열들을 하나씩 꺼내서 case에 넣고
→ case는 매번 (a,b,c) 같은 튜플이 됨
print(case)(1, 2, 3)
(1, 2, 4)
...
| 루프 횟수 | case 값 |
|---|---|
| 1번째 | (1, 2, 3) |
| 2번째 | (1, 2, 4) |
| 3번째 | (1, 3, 2) |
| ... | ... |
| 24번째 | (4, 3, 2) |
data = [1, 2, 3, 4]
가능한 순열 (3개 뽑기, 순서 O, 중복 X):
1. (1, 2, 3)
2. (1, 2, 4)
3. (1, 3, 2)
...
24. (4, 3, 2)
→ 하나씩 case 변수에 담겨서 출력됨
| 궁금한 점 | 설명 |
|---|---|
| 왜 튜플로 나오지? | permutations() 함수는 튜플로 반환함 (변경 불가능한 순서 쌍) |
| 왜 3개만 뽑아? | 두 번째 인자에 3을 줬기 때문 (r=3) |
| 중복된 숫자 나오면? | 원본 리스트에 중복이 있으면 결과에도 중복 순열이 생김 |
| 순서 바뀌면 다른 거야? | 응, 순열이니까 (1, 2, 3)과 (2, 1, 3)은 다른 경우야 |
from itertools import permutations
data = [5, 6, 7]
for p in permutations(data, 2):
print(p)
❓ 결과는 총 몇 개? 어떤 식으로 출력될까?
3P2 = 3 × 2 = 6(5, 6)
(5, 7)
(6, 5)
(6, 7)
(7, 5)
(7, 6)
좋아! 이 코드를 너가 진짜로 완벽하게 이해할 수 있도록
지금부터 아주 천천히, 한 줄씩 디버깅 흐름처럼 초보자 눈높이로 쪼개서 설명해줄게.
이전 permutations()과도 비교하면서, 무엇이 다르고 왜 그렇게 동작하는지도 정확히 잡아줄게.
from itertools import combinations
for comb in combinations([1, 2, 3, 4, 5], 3):
print(comb)
[1, 2, 3, 4, 5] 중에서combinations)을 만들어서 출력하는 코드야.from itertools import combinations📌 무슨 역할?
itertools에서 combinations() 함수만 불러옴📌 왜 있어야 해?
combinations()는 기본 내장 함수가 아님 → import 안 하면 에러남for comb in combinations([1, 2, 3, 4, 5], 3):이게 핵심이야. 이 줄을 완전히 뜯어서 설명할게.
combinations([1, 2, 3, 4, 5], 3) 뜻[1, 2, 3, 4, 5]에서| 조합 | 설명 |
|---|---|
| (1, 2, 3) | 1, 2, 3 뽑음 |
| (1, 2, 4) | 1, 2, 4 뽑음 |
| ... | ... |
| (3, 4, 5) | 마지막 조합 |
총 몇 개일까?
5C3 = 5! / (3! * (5-3)!) = 10
for comb in ...:combinations(...)는 튜플들의 이터레이터를 반환해comb 변수에 하나씩 꺼내서 반복print(comb)(1, 2, 3)
(1, 2, 4)
(1, 2, 5)
(1, 3, 4)
(1, 3, 5)
(1, 4, 5)
(2, 3, 4)
(2, 3, 5)
(2, 4, 5)
(3, 4, 5)
combinations()과 permutations() 차이 정리| 항목 | combinations() | permutations() |
|---|---|---|
| 순서 | 상관 없음 ❌ | 순서 중요 ✅ |
| (1,2,3) vs (3,2,1) | 같은 조합 | 다른 순열 |
| 예제 | 복권 번호 뽑기 | 자리를 배치할 때 |
| 결과 수 | nCr (작음) | nPr (큼) |
입력 리스트: [1, 2, 3, 4, 5]
선택 개수: 3
가능한 조합 (순서 X):
--------------------------------
1. (1, 2, 3)
2. (1, 2, 4)
3. (1, 2, 5)
4. (1, 3, 4)
5. (1, 3, 5)
6. (1, 4, 5)
7. (2, 3, 4)
8. (2, 3, 5)
9. (2, 4, 5)
10. (3, 4, 5)
| 궁금한 점 | 설명 |
|---|---|
| 왜 튜플로 나와? | itertools.combinations()이 튜플로 결과 반환함 |
| 중복 허용 안 돼? | 응, 기본 combinations()은 중복 없이 뽑음 |
| 순서 바뀌면 다른 조합이야? | 아니야, (1, 2, 3)과 (3, 2, 1)은 같은 조합이라 한 번만 나와 |
from itertools import combinations
for comb in combinations([1, 2, 3, 4, 5], 3):
if sum(comb) == 10:
print(comb)
➡ 조합 중 합이 10인 것만 출력
좋아, 이제 이어서 파이썬 실전 트랩 14번, 15번을 완전히 해부해줄게.
이 두 개는 실제 정보처리기사 실기나 알고리즘 문제에서도 자주 혼동해서 틀리는 부분이야.
in 연산자 동작 방식 (문자, 리스트, 딕셔너리 다 다름)파이썬에서 in 연산자는
"이 값이 이 안에 있니?" 라는 질문을 할 때 사용하는 연산자야.
그런데 자료형에 따라 동작 방식이 미묘하게 다르다는 걸 꼭 알고 있어야 해.
inprint('a' in 'apple') # True
print('pp' in 'apple') # True
print('x' in 'apple') # False
✔️ 문자열 안에 해당 문자 또는 문자열이 포함되어 있는지 확인
→ 부분 문자열 검색
inprint(3 in [1, 2, 3]) # True
print(5 in [1, 2, 3]) # False
✔️ 리스트 안에 해당 요소가 존재하는지
ind = {'a': 1, 'b': 2}
print('a' in d) # ✅ True
print(1 in d) # ❌ False
print('b' in d.keys()) # ✅ True
print(2 in d.values()) # ✅ True
📌 딕셔너리에서 in은 기본적으로 "key"를 기준으로 검사함!
d = {'a': 1, 'b': 2}
if 2 in d:
print("있다")
✅ 이건 출력 안 됨
왜냐면 in은 key만 보기 때문에 → 2는 value라서 False
→ 2 in d.values() 로 써야 맞음
| 자료형 | in 대상 | 예시 |
|---|---|---|
| 문자열 | 부분 문자열 | 'a' in 'cat' ✅ |
| 리스트/튜플 | 요소 | 3 in [1,2,3] ✅ |
| 딕셔너리 | 기본은 key만 | 'a' in {'a':1} ✅ |
| 딕셔너리의 값 검사 | .values() 필요 | 1 in d.values() ✅ |
list)a = [1, 2, 2, 3]
print(a[0]) # 1
set)s = {1, 2, 2, 3}
print(s) # {1, 2, 3} ← 중복 제거됨
x in s (O(1))dict)d = {'a': 1, 'b': 2}
print(d['a']) # 1
key는 중복 불가key in d는 매우 빠름 (O(1))| 자료형 | 중복 허용 | 순서 유지 | 용도 |
|---|---|---|---|
| list | O (중복 허용) | O (순서 유지) | 순차 데이터 |
| set | ❌ (중복 제거됨) | ❌ (순서 X) | 존재 여부 확인, 집합 연산 |
| dict | key 중복 ❌ | O (파이썬 3.7+) | 키-값 매핑 |
items = [1, 2, 2, 3, 4]
unique = set(items)
print(len(unique)) # 4 ← 중복 제거됨
a = {1, 2, 3}
b = {2, 3, 4}
print(a & b) # {2, 3} ← 교집합
print(a | b) # {1, 2, 3, 4} ← 합집합
print(a - b) # {1} ← 차집합
| 주제 | 핵심 포인트 | 주의점 |
|---|---|---|
in 연산자 | 포함 여부 검사 | 딕셔너리는 key만 검사함 |
| list | 순서 있음, 중복 O | 인덱싱 가능 |
| set | 순서 없음, 중복 ❌ | 빠른 탐색용 |
| dict | key-value 구조 | key만 중복 ❌ |