imhamburger 님의 블로그
파이썬(Python) - 순열(Permutation)과 조합(Combination) 구현하기 본문
1. 순열(Permutation)
순열은 순서가 부여된 임의의 집합을 다른 순서로 뒤섞는 연산이다.
[1, 2, 3] 이라는 숫자들을 가지고 순열을 구현해보자.
그림으로 나타내면 다음과 같다.
경우의 수는 총 6개이다.
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
그리고 숫자들을 각각 i, j, k 라고할 때,
i, j, k
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
잘 살펴보면 규칙이 있다.
- i 에 나왔던 수는 j 에 나오지 않는다.
- i 와 j 에 나왔던 수는 k 에 나오지 않는다.
1-1 반복문 사용
규칙을 이용해 반복문으로 구현해보자.
for i in range(1, 4):
for j in range(1, 4):
if i == j : continue #i와 j가 같다면 무시
for k in range(1, 4): #i와 j가 같지않다면 k반복문 실행
if i == k or j == k: continue #i==k 혹은 j==k 라면 무시
print(i, j, k) #아니라면 출력
#출력값
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
위 반복문에 continue가 있는 코드를 "use" 라는 배열을 준비해 1, 2, 3에 대해 "사용됐다" 혹은 "사용되지 않았다"를 구분할 것이다.
예를들어, use[1] = 1 이면 사용중이고 use[2] = 0 이면 사용중이 아닌 것이다.
use = [0] * 4
for i in range(1, 4):
use[i] = 1
for j in range(1, 4):
if use[j] : continue #use[j]가 사용중이라면 무시
use[j] = 1 #아니라면 사용중으로 해줘
for k in range(1, 4):
if use[k] : continue #use[k]가 사용중이라면 무시
use[k] = 1 #아니라면 사용중으로 해줘
print(i, j, k)
use[k] = 0
use[j] = 0
use[i] = 0
#출력값
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
여기에서 i, j, k 가 별도로 리스트로 저장되기를 원한다면? arr 이라는 배열을 만들어 넣어주면 된다.
use = [0] * 4
arr = [0] * 3
for i in range(1, 4):
use[i] = 1
arr[0] = i
for j in range(1, 4):
if use[j] : continue
use[j] = 1
arr[1] = j
for k in range(1, 4):
if use[k] : continue
use[k] = 1
arr[2] = k
print(arr)
arr[2] = 0
use[k] = 0
arr[1] = 0
use[j] = 0
arr[0] = 0
use[i] = 0
#출력값
[1 2 3]
[1 3 2]
[2 1 3]
[2 3 1]
[3 1 2]
[3 2 1]
1-2 재귀 사용
위에 반복문을 이용하면 데이터가 늘어난다면 반복문도 끝없이 늘어나는 문제가 있다....!
따라서 재귀를 사용해줘야 한다.
data = [1, 2, 3] #데이터
n = len(data) #데이터 개수
use = [0] * n #데이터를 사용중인가 아닌가? use[1] = 1 이면 사용중
arr = [0] * n #어떤 데이터를 선택했는가? arr[1] = 2 이라면 내가 두번째로 뽑은 숫자는 2 가 되는 것이다.
def permutation(level): #level은 위에 그림에서 파란색
if level >= n:
print(arr)
return
for i in range(n):
if use[i] : continue
use[i] = 1 #i 인덱스에 있는 데이터 사용중
arr[level] = data[i]
permutation(level+1)
arr[level] = 0
use[i] = 0 #사용해제
permutation(0)
#출력값
[1 2 3]
[1 3 2]
[2 1 3]
[2 3 1]
[3 1 2]
[3 2 1]
2. 조합(Combination)
조합은 데이터 집합에서 서로 다른 n개의 원소 중 순서에 상관없이 k개를 선택하는 것이다.
만약 {1, 2, 3, 4} => 2개를 선택한다고 할 때 {1, 2} , {2, 1} 은 값은 같은 경우이다. {1, 2} == {2, 1}
따라서 한 가지만 경우의 수로 사용한다.
[1, 2, 3, 4] 이라는 숫자들을 가지고 2개를 선택해 조합한다면 경우의 수는 다음과 같다.
[1, 2]
[1, 3]
[1, 4]
[2, 3]
[2, 4]
[3, 4]
총 6개이다.
리스트 안에 있는 숫자들을 각각 i 와 j 라고 하였을 때,
i j
[1, 2]
[1, 3]
[1, 4]
[2, 3]
[2, 4]
[3, 4]
여기에도 규칙이 있다.
- i 는 데이터 개수가 4개일 때 3까지 뽑는다. 즉, n-1
- j는 (i + 1) 부터 마지막 n개까지 뽑는다.
2-1 반복문 사용
규칙을 이용해 반복문으로 구현해보자.
#n개 데이터에서 2개 데이터 뽑기
data = [1, 2, 3, 4]
def func(n):
for i in range(n-1):
for j in range(i+1, n):
print(data[i], data[j])
func(data[n])
#출력값
1, 2
1, 3
1, 4
2, 3
2, 4
3, 4
반복문으로 조합을 구현할 수 있지만, 문제가 있다.
데이터 수가 달라지는 경우는 상관없지만 k개가 달라지는 경우 for문을 추가/감소 해야하는 작업이 필요하다.
#n개 데이터에서 3개 데이터 뽑기
n = 5
def func(n):
for i in range(n-2):
for j in rnage(i+1, n-1):
for k in range(j+1, n):
print(i, j, k)
이 문제를 해결하기 위해선 재귀를 사용해야 한다.
2-2 재귀 사용
#N개 데이터에서 k개 데이터 뽑기
#level: 몇번째 선택을 하는 것인가!
N = 4
k = 3
arr = [0] * k
A = [1, 2, 3, 4]
def combi(level, S):
#종료조건
if level == k:
print(arr)
return
for i in range(S, N-k+level+1):
arr[level] = A[i]
combi(level+1, i+1)
combi(0, 0)
#출력값
[1, 2, 3]
[1, 2, 4]
[1, 3, 4]
[2, 3, 4]
'파이썬(Python)' 카테고리의 다른 글
파이썬(Python) - 파이썬으로 이메일 보내기 (with Google) (0) | 2024.11.01 |
---|---|
파이썬(Python) - MANIFEST.in 개념 이해하기 + 생성하기 (0) | 2024.09.02 |
파이썬(Python) - if __name__=="__main__"의 의미 이해하기 (0) | 2024.08.22 |
파이썬(Python) - Requests GET 요청, POST 요청 (0) | 2024.08.02 |
파이썬(Python) - 환경변수 불러오기 os.getenv (0) | 2024.07.31 |