순열 (Permutation)
- 서로 다른 것들 중 몇 개를 뽑아서 한 줄로 나열하는 것
- 서로 다른 n개 중 r개를 택하는 순열은 nPr
순열을 생성하는 방법
- 반복문을 통한 순열 생성 : 순열의 갯수가 적을때, 순열의 길이가 변동이 없을때
- 재귀 호출을 통한 순열 생성 : boolean[ ] 사용
- 비트마스킹을 통한 순열 생성 : 정수와 비트연산자를 사용
- 현 순열에서 사전 순으로 다음 순열 생성 ( NextPermutation )
- 배열을 오름차순으로 정렬한 후 시작
- 아래 과정을 반복하여 사전 순으로 다음으로 큰 순열 생성
- 뒤쪽부터 탐색하며 교환위치 ( i-1 ) 찾기 ( i:꼭대기 )
- 뒤쪽부터 탐색하며 교환위치 ( i-1 )와 교환할 큰 값 위치 ( j ) 찾기
- 두 위치 값 ( i-1, j ) 교환
- 꼭대기위치 ( i ) 부터 맨 뒤까지 오름차순 정렬
기본 코드
import java.util.Arrays;
public class perm {
static int n = 5, r = 3;
static int[] numbers;
static boolean[] isSelected;
public static void main(String[] args) {
numbers = new int[r];
isSelected = new boolean[n + 1];
perm(0);
}
public static void perm(int cnt) {
if (cnt == r) {
System.out.println(Arrays.toString(numbers));
return;
}
for (int i = 1; i <= n; i++) {
if (isSelected[i]) continue;
numbers[cnt] = i;
isSelected[i] = true;
perm(cnt+1);
isSelected[i] = false;
}
}
}
조합(Combination)
- 서로 다른 n개의 원소 중 r개를 순서 없이 골라낸 것을 조합
- 조합의 수식
- nCr = n! / (n-r)! r!
- nCr = n-1Cr-1 + n-1Cr, nC0=1
조합을 생성하는 방법
- 반복문을 통한 조합 생성
- 재귀 호출을 이용한 조합 생성
- NextPermutation을 활용
- 원소 크기와 같은 크기의 int 배열 P를 생성하여 r개 크기 만큼 뒤에서 0이 아닌 값으로 초기화 (ex, 1로 초기화)
- nextPermutation 알고리즘 한 번 수행시마다 조합이 생성됨
- P 배열에서 0이 아닌 값을 갖고 있는 위치에 해당하는 원소가 조합에 선택된 것
기본 코드
import java.util.Arrays;
public class comb {
static int n = 5, r = 3;
static int[] numbers;
public static void main(String[] args) {
numbers = new int[r];
comb(0, 0);
}
public static void comb(int cnt, int start) {
if (cnt == r) {
System.out.println(Arrays.toString(numbers));
return;
}
for (int i = start; i <= n; i++) {
numbers[cnt] = i;
comb(cnt + 1, i + 1);
}
}
}
부분 집합(Subset)
- 집합에 포함된 원소들을 선택
- 원소들의 그룹에서 최적의 부분 집합을 찾는 것
- N개의 원소를 포함한 집합
- 자기 자신과 공집합을 포함한 모든 부분집합(Power set)의 개수는 2^n개
- 원소의 수가 증가하면 부분집합의 개수는 지수적으로 증가
부분 집합 생성 방법
- 반복문을 통한 부분집합 생성
- 재귀 호출을 이용해 생성 : Visited를 이용
- 바이너리 카운팅을 통한 사전적 순서로 생성
바이너리 카운팅 (Binary Counting)
- 원소 수에 해당하는 N개의 비트열을 이용
- n번째 비트값이 1이면 n번째 원소가 포함되었음을 의미
기본 코드
public class subset {
static int n = 4;
static int[] input;
static boolean[] isSelected;
public static void main(String[] args) {
input = new int[] {1,2,3,4};
isSelected = new boolean[n];
subset(0);
}
public static void subset(int cnt) {
if (cnt == n) {
for (int i = 0; i < n; i++) {
if (isSelected[i]) {
System.out.print(input[i] + " ");
}
}
System.out.println();
return;
}
isSelected[cnt] = true;
subset(cnt+1);
isSelected[cnt] = false;
subset(cnt+1);
}
}
'Algorithm > 정리' 카테고리의 다른 글
[알고리즘] 최장 공통 부분 수열 (LCS, Longest Common Subsequence) (0) | 2022.07.02 |
---|---|
진수 변환 (10진수 > n진수 / n진수 > 10진수) (0) | 2022.03.16 |