순열


순열

  • 하나의 집합을 다른 순서로 뒤섞는 것
  • n개의 집합에서 순열의 총 개수는 n!
    ex) n = 5, 5x4x3x2x1 = 순열의 총 개수
  • nPr 수식 (P = Permutation 약자)
    3P2 = 3! / (3-2)!
            = 6 / 1
            = 6   (1, 2) / (1, 3) / (2, 1) / (2, 3) / (3, 1) / (3, 2) 총 6개
  • 재귀로 구현 가능
    자주 사용되는 swap, visited 방법으로 구현
  • 완전탐색 문제에서도 자주 나올 수 있음

 

swap을 이용한 순열

  • 배열의 값을 직접 교환해서 구함
  • Depth를 이용한 풀이
  • Depth와 r의 값이 같으면 모두 다 뽑았다는 것이므로 결과값 출력
  • 순열 함수가 종료됐을 때 배열의 값을 다시 원상복구 해주어야 함
    (그 다음 수와 다시 순열을 계산해야 하므로)

구현
주석으로 설명했으나, 제일 빠른건 직접 디버깅하면서 확인해보면 된다.

public static void swapPermutation(int[] arr, int depth, int n, int r) {
    // depth와 r이 같으면 다 뽑았다는 것이므로
    if (depth == r){
        for(int i=0; i<r; i++){
            System.out.print(arr[i] + " ");
        }
        System.out.println();
        return;
    }
    else {
        /*
            1, 2, 3 세 개의 숫자를 순열로 구한다고 했을 때,
            재귀의 특성 상
            depth가 0일 경우 1XX, 2XX, 3XX을 구해야 함
            depth가 1일 경우 12X, 13X 를 구해야 함
            depth가 2일 경우 123, 132 를 구해야 함
            depth == r에서 return 되면서 배열을 원상복구 시킨 후
            depth가 0일 경우 2XX, 3XX 를 구하는 과정을 반복
         */
        for(int i=depth; i<n; i++){
            swap(arr, i, depth);
            swapPermutation(arr, depth + 1, n, r);
            swap(arr, i, depth);
        }
    }
}

public static void swap(int[] arr, int i, int j){
    int tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}

 

visited을 이용한 순열

  • 방문했는지 확인할 수 있는 visited 배열과, 결과를 저장할 수 있는 result 배열이 필요함
  • Depth를 이용한 풀이
  • Depth와 r의 값이 같으면 모두 다 뽑았다는 것이므로 결과값 출력
  • visited를 통해 result에 데이터 저장 시 중복값이 들어가지 않도록 함

구현

public static void visitedPermutation(int[] arr, boolean[] visited, int[] result, int depth, int n, int r) {
    if (depth == r){
        for(int i : result){
            System.out.print(i + " ");
        }
        System.out.println();
        return;
    }
    else {
        for(int i=0; i<n; i++){
            if (!visited[i]){
                visited[i] = true;
                result[depth] = arr[i];
                visitedPermutation(arr, visited, result, depth + 1, n, r);
                visited[i] = false;
            }
        }
    }
}

 

결과비교

결과를 살펴보면 아래와 같다.

swap을 이용한 순열과 visited를 이용한 순열의 데이터를 비교해보면, 

swap에서는 3, 2, 1 / 3, 1, 2 순으로 출력이 되는데 visited에서는 3, 1, 2 / 3, 2, 1 순으로 출력이 된다.

따라서 swap을 이용해서 순열을 구했을 때는 순서대로 순열이 구해지지 않는다는 차이점을 발견할 수 있다. 

+ Recent posts