OPEN HYPER STEP
← 목록으로 (math)
MATH · 18 / 45
math
CHAPTER 18 / 45
읽기 약 2
FUNCTION

순열: 순서가 중요한 경우의 수


핵심 개념

nPr = n!/(n-r)! — 비밀번호 강도, URL 라우트 조합, 추천 순서. itertools.permutations.

본문

순열 공식

📋 코드 (9줄)
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

PYTHON📋 코드 (31줄)
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

실전 — 비밀번호 강도

PYTHON📋 코드 (28줄)
# 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 라우트 우선순위

PYTHON📋 코드 (15줄)
# 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순위: 캐치올
]

실전 — 추천 시스템 순서

PYTHON📋 코드 (27줄)
# 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