순열이란 n개중 r개를 순서를 가지고 선택하는 방법의 수를 의미한다. 즉, (1,2)와 (2,1)이 다른 경우이다.
자바에서는 해당 코드를 구현하기 위해 swap을 통해 첫번째 값부터 고정시켜가며 구한다.
import java.util.ArrayList;
class Permutation {
private final int n;
private final int r;
private final int[] now;
private final ArrayList<ArrayList<Integer>> result;
/**
* nPr에 n과 r 이다.
* @param n 대상의 수
* @param r 선택할 수
*/
public Permutation(int n, int r) {
this.n = n;
this.r = r;
this.now = new int[r];
this.result = new ArrayList<>();
}
public void swap(ArrayList<Integer> arr, int i, int j) {
int temp = arr.get(i);
arr.set(i, arr.get(j));
arr.set(j, temp);
}
/**
* swap하여 앞에서부터 하나씩 고정시켜 개수를 구함
* @param arr 대상
* @param depth 현재 선택된 수
*/
public void permutation(ArrayList<Integer> arr, int depth) {
// 원하는 개수에 도달하면 결과에 저장
if (depth == r) {
ArrayList<Integer> temp = new ArrayList<>();
for (int i = 0; i < now.length; i++) {
temp.add(now[i]);
}
result.add(temp);
return;
}
for (int i = depth; i < n; i++) {
swap(arr, i, depth);
now[depth] = arr.get(depth);
permutation(arr, depth + 1);
swap(arr, i, depth);
}
}
}
순서의 관계없이 n개중 r개를 선택하는 경우의 수를 구하는 것이다. 여기선 (1,2)와 (2,1)이 같다.
선택대상이 되는 배열의 앞에서부터 하나씩 선택하거나 선택하지 않는 방법으로 진행해나간다.
public class Combination {
private final int n;
private final int r;
private final int[] now;
private final ArrayList<ArrayList<Integer>> result;
/**
* nCr에 n과 r 이다.
* @param n 대상 수
* @param r 선택할 수
*/
public Combination(int n, int r) {
this.n = n;
this.r = r;
this.now = new int[r];
this.result = new ArrayList<>();
}
/**
* 앞에서부터 순서대로 해당 index의 값을 포함하거나 포함하지 않는 방식으로 구한다.
* @param arr 원하는 값
* @param depth 현재 세어진 개수(무조건 0 넣기)
* @param index 현재까지 도달한 index
* @param target 앞에서부터 진행된 수(더이상 값이 없는 끝에 도달하면 멈추기 위함)
*/
public void combination(ArrayList<Integer> arr, int depth, int index, int target) {
// nCr에서 r에 도달하면 원하는 결과이므로 추가
if (depth == r) {
ArrayList<Integer> temp = new ArrayList<>();
for (int i = 0; i < now.length; i++) {
temp.add(arr.get(now[i]));
}
result.add(temp);
return;
}
// 끝까지 도달하면 그냥 리턴
if (target == n) {
return;
}
now[index] = target;
// 해당 인덱스를 포함하는 조합
combination(arr, depth + 1, index + 1, target + 1);
// 해당 인덱스를 포함하지 않는 조합
combination(arr, depth, index, target + 1);
}
}
확실히 순열보다 빠르다.
파이썬에서는 순열, 조합을 itertools
라는 기본 라이브러리에서 제공한다.
import itertools
data = [1, 2, 3, 4, 5]
# 순열(ex. 5C2)
for x in itertools.permutations(data, 2):
print(list(x), end=' ')
# 조합(ex. 5P2)
for x in itertools.combinations(data, 2):
print(list(x), end=' ')
파이썬이 코딩테스트로는 역시 꿀인것 같다.🤯