순열, 조합

김명일·2022년 6월 14일

전체 소스코드

순열

순열이란 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);
        }
    }

}

테스트 결과

  • 500개중 3개 선택: 실패
  • 300개중 3개 선택: 3354ms
  • 100개중 3개 선택: 189ms

조합

순서의 관계없이 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);
    }


}

결과

  • 500개중 3개 선택: 1810ms
  • 100개중 3개 선택: 34ms

확실히 순열보다 빠르다.

파이썬에서의 순열 조합

파이썬에서는 순열, 조합을 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=' ')

파이썬이 코딩테스트로는 역시 꿀인것 같다.🤯

profile
주니어 백엔드 🐶🦶🏻📏

0개의 댓글