일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 인스타
- 데베시 1주차
- Git
- 백준
- 참고X
- git 오류
- DP
- 코테
- Workbench
- c언어
- c언어 제어문
- 최단거리
- 5장
- 4장
- 스택
- 파이썬 알고리즘 인터뷰
- 그리디
- 자료구조
- git기초
- python기초
- 코딩테스트
- 도커
- 1주차(1)
- git오류
- 운체 1주차
- python자료형
- 인텔리제이
- #코린이 #코딩 #할 수 있다
- c언어 기본
- python기본
- Today
- Total
하루살이 개발자
[알고리즘] 순열과 조합 본문
코딩테스트에서 자주 만났던 순열과 조합에대해 정리해보려고 합니다!
순서, 중복여부에 따라서 순열, 조합, 중복순열, 중복조합으로 나뉜다.
종류 | 순열 | 중복순열 | 조합 | 중복조합 |
순서 다름 구분 여부 | O | O | X | X |
중복 여부 | X | O | X | O |
{1, 2, 3}, r = 2일 경우 | 1 2 1 3 2 1 2 3 3 1 3 2 |
1 1 1 2 1 3 2 1 2 2 2 3 3 1 3 2 3 3 |
1 2 1 3 2 3 |
1 1 1 2 1 3 2 1 2 2 2 3 3 1 3 2 3 3 |
특징 | 원소저장 배열 result 필요 방문처리 배열 visited 필요 탐색 시작기준 start 필요X |
원소저장 배열 result 필요 방문처리 배열 visited 필요X 탐색 시작기준 start 필요X |
원소저장 배열 result 필요X 방문처리 배열 visited 필요 탐색 시작기준 start 필요 |
원소저장 배열 result 필요 방문처리 배열 visited 필요X 탐색 시작기준 start 필요 |
[특징 비교 정리]
원소저장 배열 result -> 조합을 뺀 나머지 순열/중복순열/중복조합에서 필요
방문처리 배열 visited -> 중복허용이 안되는 순열/조합에서 필요
탐색 시작기준 start -> 순서가 달라도 같은것으로 보는 조합/중복조합만 필요
depth, r -> 모두 필요
1. 순열 - Permutation
서로 다른 n개에서 r개를 뽑아 "정렬"하는 경우의 수 -> 순서O, 중복X
ex) {1, 2}이 주어질 때 순열에서는 순서만 다른 [1, 2]와 [2, 1]을 다른 것으로 인식한다.
JAVA 코드로 순열 코드를 짜면 다음과 같다.
public class 순열 {
public static void permutation(int[] arr, int[] result, boolean[] visited, int depth, int r){
// 순열 출력
if(depth == r){
for(int num : result){
System.out.print(num);
System.out.print(" ");
}
System.out.println();
return;
}
for(int i = 0; i < arr.length; i++){
if(!visited[i]){
// 방문처리
visited[i] = true;
result[depth] = arr[i]; // 값 넣기
permutation(arr, result, visited, depth+1, r); // 재귀
visited[i] = false;
}
}
}
public static void main(String[] args){
int[] arr = {1, 2, 3};
int r = 2;
int[] result = new int[r];
boolean[] visited = new boolean[arr.length];
permutation(arr, result, visited, 0, r);
}
}
- result: 순서대로 방문하는 원소를 저장하는 배열
- 중복이 불가능하기 때문에 visited를 이용해서 이미 선택한 원소를 다시 선택하지 않도록 해준다.
2. 중복순열
서로 다른 n개에서 "중복이 가능"하게 r개를 뽑아 정렬하는 경우의 수 -> 순서O, 중복O
JAVA 코드로 중복순열 코드를 짜면 다음과 같다.
public class 중복순열 {
public static void permutation(int[] arr, int[] result, int depth, int r){
// 중복순열 출력
if(depth == r){
for(int num : result){
System.out.print(num);
System.out.print(" ");
}
System.out.println();
return;
}
for(int i = 0; i < arr.length; i++){
result[depth] = arr[i];
// 중복허용이므로 방문체크 불필요
permutation(arr, result, depth+1, r);
}
}
public static void main(String[] args) {
int[] arr = {1, 2, 3};
int r = 2;
int[] result = new int[r];
permutation(arr, result, 0, r);
}
}
- 순열과 유일한 차이는 중복이 가능하다는 것이다. 따라서 순열코드에서 중복을 방지하기 위해 사용했던 visited가 필요없다.
3. 조합 - Combination
서로 다른 n개에서 "순서 없이" r개를 뽑는 경우의 수 -> 순서X, 중복X
ex) {1, 2}이 주어질 때 조합에서는 순서가 다른 [1, 2]와 [2, 1]을 같은 것으로 인식한다.
JAVA 코드로 조합 코드를 짜면 다음과 같다.
public static void combination(int[] arr, boolean[] visited, int start, int depth, int r){
if(depth == r){
for(int i = 0; i < arr.length; i++) {
if (visited[i]) {
System.out.print(arr[i]);
System.out.print(" ");
}
}
System.out.println();
return;
}
for(int i = start; i < arr.length; i++){
if(!visited[i]){
visited[i] = true; // 방문체크
combination(arr, visited, i+1, depth+1, r);
visited[i] = false;
}
}
}
public static void main(String[] args) {
int[] arr = {1, 2, 3};
int r= 2;
boolean[] visited = new boolean[arr.length];
combination(arr, visited, 0, 0, r);
}
- 순서가 상관없고 중복을 허용하지 않기 때문에, 탐색의 시작 기준을 start로 하고 visited를 이용하여 중복여부를 확인한다.
- 재귀 호출 시 start와 depth 모두 +1 해준다.
4. 중복조합
서로 다른 n개에서 순서 없이, "중복 가능"하게 r개를 뽑는 경우의 수 -> 순서X, 중복O
JAVA 코드로 중복조합 코드를 짜면 다음과 같다.
public class 중복조합 {
public static void combination(int[] arr, int[] result, int start, int depth, int r){
// 중복조합 출력
if(depth == r){
for(int num : result){
System.out.print(num);
System.out.print(" ");
}
System.out.println();
return;
}
for(int i = 0; i < arr.length; i++){
result[depth] = arr[i];
combination(arr, result, i, depth+1, r);
}
}
public static void main(String[] args) {
int[] arr = {1, 2, 3};
int r = 2;
int[] result = new int[r];
combination(arr, result, 0, 0, r);
}
}
- 조합과 유일한 차이는 중복이 가능한 것이므로 visited가 불필요하다.
- 현재 사용한 원소보다 뒤의 것만 선택가능한 것이 아니라, 현재 원소를 포함하여 그 뒤의 것들까지 선택가능하므로 재귀 호출에서 start를 i+1로 넘기던 것을 그냥 i로 넘기면 된다.
이제 코테에서 순열,조합 나오면 잘 풀 수 있겠지!?
'CS > 알고리즘' 카테고리의 다른 글
[알고리즘] 최소 신장 트리(Kruskal, Prim 알고리즘) (0) | 2022.02.23 |
---|---|
[알고리즘] 최대공약수(유클리드 호제법) / 최소 공배수 (0) | 2022.02.23 |
[알고리즘] union-find 알고리즘 (0) | 2022.02.20 |
[알고리즘] 소수찾기 - 에라토스테네스의 체 (0) | 2022.02.16 |
[알고리즘] 우선순위 큐 (Priority Queue) (0) | 2022.02.16 |