math
CHAPTER 18 / 45
읽기 약 2분
FUNCTION
순열: 순서가 중요한 경우의 수
핵심 개념
nPr = n!/(n-r)! — 비밀번호 강도, URL 라우트 조합, 추천 순서. itertools.permutations.
본문
순열 공식
nPr = n × (n-1) × (n-2) × ... × (n-r+1)
= n! / (n-r)!
예: 5개 중 3개 순서대로 선택
5P3 = 5 × 4 × 3 = 60
특수 케이스:
nPn = n! (전체 순서)
nP0 = 1 (선택 없음 = 1가지)Python itertools.permutations
import itertools
# 모든 순열 (전체 순서)
items = ['A', 'B', 'C']
for p in itertools.permutations(items):
print(p)
# ('A', 'B', 'C')
# ('A', 'C', 'B')
# ('B', 'A', 'C')
# ('B', 'C', 'A')
# ('C', 'A', 'B')
# ('C', 'B', 'A')
# 총 3! = 6가지
# r개 선택 (5P3 = 60)
items = ['A', 'B', 'C', 'D', 'E']
perms_3 = list(itertools.permutations(items, 3))
print(len(perms_3)) # 60
# 직접 구현 (수학 검증용)
import math
def nPr(n, r):
return math.factorial(n) // math.factorial(n - r)
print(nPr(5, 3)) # 60
print(nPr(10, 4)) # 5040
print(nPr(5, 5)) # 120실전 — 비밀번호 강도
# 8자리 비밀번호의 경우의 수
scenarios = {
'숫자만': (10, 8), # 0~9 from 10
'소문자만': (26, 8), # a~z from 26
'소문자+숫자': (36, 8),
'대소문자+숫자': (62, 8),
'대소문자+숫자+특수': (95, 8),
}
print(f"{'시나리오':<20} {'경우의 수':<25} {'무차별 시도 시간(1억/초)'}")
print("-" * 80)
for name, (chars, length) in scenarios.items():
total = chars ** length
seconds = total / 100_000_000
if seconds < 60: time_str = f"{seconds:.1f}초"
elif seconds < 3600: time_str = f"{seconds/60:.1f}분"
elif seconds < 86400: time_str = f"{seconds/3600:.1f}시간"
elif seconds < 365*86400: time_str = f"{seconds/86400:.1f}일"
else: time_str = f"{seconds/(365*86400):.0f}년"
print(f"{name:<20} {total:<25,} {time_str}")
# 결과:
# 숫자만 100,000,000 1.0초
# 소문자만 208,827,064,576 34.8분
# 소문자+숫자 2,821,109,907,456 7.8시간
# 대소문자+숫자 218,340,105,584,896 25.3일
# 대소문자+숫자+특수 6,634,204,312,890,625 2년+실전 — URL 라우트 우선순위
# Next.js 같은 프레임워크에서 동적 라우트 우선순위는 등록 순서에 따라 다름
# /[lang]/[id] vs /[id]/[lang] 결과가 다름
routes = ['static', '[lang]', '[id]', '[...rest]']
# 모든 우선순위 조합 시도
print(f"가능한 라우트 우선순위: {math.factorial(len(routes))}가지") # 24
# Next.js 권장 순서
recommended = [
'static', # 1순위: 정적 라우트
'[lang]', # 2순위: 명명된 동적
'[id]', # 3순위: 다른 명명된 동적
'[...rest]', # 4순위: 캐치올
]실전 — 추천 시스템 순서
# 5개 상품 중 3개를 순서대로 노출 (순서가 클릭률에 영향)
import itertools
products = ['상품A', '상품B', '상품C', '상품D', '상품E']
# 모든 가능한 노출 순서
top3_orders = list(itertools.permutations(products, 3))
print(f"가능한 Top 3 순서: {len(top3_orders)}가지") # 60
# A/B 테스트로 최적 순서 찾기 — 단, 60가지 모두 테스트 X
# 실전: 휴리스틱 + ML로 후보 순서 5~10개로 축소 → 테스트
# 휴리스틱: 최근 클릭 순 + 가격 순 + 평점 순
def rank_products(products, scoring_fn):
return sorted(products, key=scoring_fn, reverse=True)
products_with_score = [
{'name': '상품A', 'click_rate': 0.05, 'price': 10000, 'rating': 4.5},
{'name': '상품B', 'click_rate': 0.08, 'price': 15000, 'rating': 4.2},
{'name': '상품C', 'click_rate': 0.03, 'price': 8000, 'rating': 4.8},
]
ranked = rank_products(products_with_score, lambda p: p['click_rate'] * p['rating'])
for p in ranked[:3]:
print(p['name'])다음 챕터
CH.19 "조합" — 순서가 필요 없는 선택 + 팀 구성·로또 확률.
AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
Claude
무료: Sonnet 4.6 / Pro $20/mo: Opus 4.6
내 비밀번호 정책의 강도를 분석해서 무차별 공격 시간 + 권장 정책을 수학적 근거와 함께 보고해줘.
ChatGPT
무료: GPT-5.5 / Plus $20/mo: GPT-5.5 Pro
한국 OTP/2FA 시스템의 경우의 수 설계와 실제 보안 강도를 비교 분석해줘.
Gemini
무료: 2.5 Flash / Pro $19.99/mo: 3.1 Pro
내 추천 시스템의 노출 순서 패턴을 분석해서 A/B 테스트 가능한 후보 10개와 ROI를 만들어줘.
Grok
무료: Grok 4.1 / SuperGrok $30/mo
2026년 인증 보안에서 패스워드 vs 패스키 전환 트렌드와 실제 효과를 솔직히 알려줘.
⭐ 이것만 기억하세요
순열: 순서가 중요한 경우의 수는 이 3가지만 확실히 잡으세요
1.순열 nPr = n!/(n-r)! — 순서가 의미를 갖는 모든 선택의 경우의 수
2.비밀번호 강도는 (문자 종류)^(길이)로 결정 — 길이 1↑이 종류 1↑보다 효과적
3.다음 챕터 CH.19에서 조합 — 순서가 무관한 경우의 수와 파스칼의 삼각형
공유하기
진행도 18 / 45