1. 순열(Permutation)의 기본 개념
1.1 순열이란?
- 순열은 n개의 원소 중에서 r개를 선택하여 순서대로 나열하는 것을 말합니다.
수학적 표현
- 기호: nPr 또는 P(n,r)
- 공식: nPr = n!/(n-r)!
- (n-r)!로 나누는 이유는 선택하지 않은 원소들의 순서는 고려하지 않기 때문입니다.
예시로 이해하기
3개의 숫자 [1,2,3]으로 만들 수 있는 모든 순열:
[1,2,3]
[1,3,2]
[2,1,3]
[2,3,1]
[3,1,2]
[3,2,1]
중요 포인트
- 순서가 중요합니다 ([1,2,3]과 [1,3,2]는 다른 순열)
- n개를 모두 사용하는 순열의 개수는 n!개
- 순열은 사전순으로 나열할 수 있습니다
2. Next Permutation 알고리즘
2.1 알고리즘의 원리
왜 Next Permutation이 필요한가?
- 모든 순열을 저장하지 않고도 순서대로 생성할 수 있습니다
- 메모리를 효율적으로 사용할 수 있습니다
- 특정 순열의 '다음' 순열을 O(n) 시간에 찾을 수 있습니다
사전순 배열의 특성
예를 들어 [1,2,3,4]로 만들 수 있는 순열들의 일부를 보겠습니다:
...
[1,4,3,2]
[2,1,3,4] <- 더 큰 순열
[2,1,4,3]
...
중요한 관찰:
- 뒤에서부터 보면, 숫자가 감소하는 부분(내림차순)이 있습니다
- 내림차순이 깨지는 지점이 '교체 포인트'가 됩니다
- 이 지점을 기준으로 다음 순열이 만들어집니다
2.2 내림차순을 찾는 이유
순열에서 숫자가 내림차순으로 정렬된 부분은 해당 부분에서 만들 수 있는 가장 큰 순열을 의미합니다.
예시로 이해해봅시다. [6,2,1,5,4,3,0] 에서:
6,2,1,[5,4,3,0]
↑ ↑
A B
- A: 내림차순이 깨지는 지점 (1)
- B: 내림차순 시작 지점 (5,4,3,0은 내림차순)
이게 중요한 이유는:
- 내림차순 부분은 이미 해당 숫자들로 만들 수 있는 가장 큰 순열입니다
- 더 큰 순열을 만들려면, 내림차순이 깨지는 지점(A)의 숫자를 교체해야 합니다
- A의 숫자보다 크면서 가장 작은 숫자와 교체해야 '다음' 순열이 됩니다
2.3 알고리즘 단계별 설명
[6,2,1,5,4,3,0] 예시로 진행과정을 보겠습니다:
- 내림차순 찾기
6,2,1,[5,4,3,0]
- 뒤에서부터 내림차순 찾기: [5,4,3,0]
- 1이 내림차순이 깨지는 지점
- 교체할 숫자 찾기
6,2,1,5,4,3,0
↑ ↑
1과 3을 교체
- 1보다 크면서 가장 작은 수인 3을 찾음
- 1과 3을 교체
- 재정렬
6,2,3,5,4,1,0 -> 교체 후
6,2,3,0,1,4,5 -> 최종 결과
- 교체한 위치(3) 이후의 숫자들을 오름차순으로 정렬
- 이렇게 하면 사전순으로 다음에 오는 가장 작은 순열이 됨
2.4 Python 구현
def next_permutation(arr):
# 1. 뒤에서부터 내림차순이 깨지는 지점 찾기
i = len(arr) - 2
while i >= 0 and arr[i] >= arr[i + 1]:
i -= 1
if i == -1: # 전체가 내림차순이면 마지막 순열
return False
# 2. arr[i]보다 크면서 가장 작은 수 찾기
j = len(arr) - 1
while arr[j] <= arr[i]:
j -= 1
# 3. 두 수 교체
arr[i], arr[j] = arr[j], arr[i]
# 4. i+1부터 끝까지 뒤집기
left = i + 1
right = len(arr) - 1
while left < right:
arr[left], arr[right] = arr[right], arr[left]
left += 1
right -= 1
return True
# 사용 예시
arr = [6,2,1,5,4,3,0]
print("현재 순열:", arr)
next_permutation(arr)
print("다음 순열:", arr)
시간 복잡도
- 한 번의 next_permutation 호출: O(n)
- 뒤집기 연산: O(n)
- 전체 메모리: O(1) (추가 메모리 불필요)
3. 조합(Combination)
3.1 조합의 수학적 정의
조합은 n개 중에서 r개를 선택하는 것을 의미하며, 순서는 고려하지 않습니다.
수식 표현
- 기호: nCr 또는 C(n,r)
- 공식: nCr = n!/((n-r)! × r!)