Publish:

태그: , ,

카테고리:

순열의 개념

순열을 알려면 조합도 알아야 하는데, 이는 다음에 포스팅하도록 하겠다.
이후 링크를 붙이도록 하자

서로 다른 n개의 물건 중에서 r개를 택하여 한 줄로 배열하는 것을 순열이라 하고, r개 택한 종류가 같다고 해도 배열된 순서가 다르다면 이 또한 하나의 경우의 수로 따진다.
조합은 순서에 상관없이 선택한 것이라면, 순열은 순서를 따진다는 것이 차이점이다.
이러한 순열의 경우의 수를 구하는 것을 수학에서는 nPr로 나타낸다.
이러한 수학 공식을 이용하면 코드로도 쉽게 나타낼 수 있다.

수학에서는 nPr을 구하라고 하면 다음과 같다.

\[_nP_r = \frac{n!}{(n-r)!} = \frac{n \times (n-1) \times (n-2) \times \cdots \times 1}{(n-r) \times (n-r-1) \times (n-r-2) \times \cdots \times 1} = n \times \cdots \times (n-r+1)\]

다만 위와 같은 상황은 ‘경우의 수’를 구할 수 있을 뿐 순열의 종류를 구하진 않는다.
그래서 원리를 이해하고 그 상황을 이용하여 알고리즘을 구성하고자 한다.

순열 예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Input: [1, 2, 3]  3 고르기
Output: [
  [ 1, 2, 3 ], [ 1, 3, 2 ],
  [ 2, 1, 3 ], [ 2, 3, 1 ],
  [ 3, 1, 2 ], [ 3, 2, 1 ],
]

Input: [1,2,3,4]  3 고르기
Output: [
  [ 1, 2, 3 ], [ 1, 2, 4 ],
  [ 1, 3, 2 ], [ 1, 3, 4 ],
  [ 1, 4, 2 ], [ 1, 4, 3 ],
  [ 2, 1, 3 ], [ 2, 1, 4 ],
  [ 2, 3, 1 ], [ 2, 3, 4 ],
  [ 2, 4, 1 ], [ 2, 4, 3 ],
  [ 3, 1, 2 ], [ 3, 1, 4 ],
  [ 3, 2, 1 ], [ 3, 2, 4 ],
  [ 3, 4, 1 ], [ 3, 4, 2 ],
  [ 4, 1, 2 ], [ 4, 1, 3 ],
  [ 4, 2, 1 ], [ 4, 2, 3 ],
  [ 4, 3, 1 ], [ 4, 3, 2 ] 
  ]

순열 알고리즘 로직

[1,2,3] 중 2개를 골라 나열하라고 한다면 어떻게 풀어야 할까?

우선 [1,2,3] 중 한 개를 골라낸다면 [1], [2], [3] 세 가지라고 할 수 있다.
이후 남은 두 가지([2,3], [1,3], [1,2]) 중에서 또 하나를 골라야 한다. 그러면 각각 두 가지씩 고를 수 있을 것이다.

감이 왔다면 아! 하게 될 것이다.
순열은 재귀함수로 풀 수 있고, 그 재귀함수는 n개 중 1개 고르는 상황을 반복하면 된다.
언제까지? r개가 골라질 때까지!

1
2
3
4
5
6
// [1,2,3,4] 중 n개를 골라 순열을 나타내야 하는 상황이라면?
// 정의한 재귀함수를 permutation(순열)이라고 하자.
1(fixed) => permutation([2, 3, 4]) => 2(fixed) => permutation([3, 4]) => ...
2(fixed) => permutation([1, 3, 4]) => 1(fixed) => permutation([3, 4]) => ...
3(fixed) => permutation([1, 2, 4]) => 1(fixed) => permutation([2, 4]) => ...
4(fixed) => permutation([1, 2, 3]) => 1(fixed) => permutation([2, 3]) => ...

순열 코드

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
const permutation = function (arr, selectNumber) {
    // arr = n개의 요소가 들은 배열
    // selectNumber = 골라야 하는 개수 >> nPr에서의 r

    const result = [];
    // 순열을 담을 답 배열

    if (selectNumber === 1) return arr.map((el) => [el]); 
    // 1개만 선택하는 거라면 그냥 arr의 원소 개수를 담아서 내보내면 된다.
    // 또한 이 재귀함수의 마지막 상황으로 볼 수 있다.

    arr.forEach((fixed, index, origin) => {
      // fixed = 처리하는 요소(보통 element로 씀)
      // index = 처리하는 요소의 인덱스값
      // origin = forEach를 호출한 배열 = arr

      const rest = [...origin.slice(0, index), ...origin.slice(index+1)] 
      // 해당 fixed를 제외한 나머지 배열 
      const permu = permutation(rest, selectNumber - 1); 
      // 나머지에 대해서 재귀함수를 이용해 순열을 구한다.
      const attached = permu.map((el) => [fixed, ...el]); 
      // 돌아온 순열에 fixed 값을 붙인다.
      result.push(...attached); 
      // 답을 집어넣을 result 배열에 spread로 push
    });

    return result;
}

이로서 순열을 구하는 방법을 알았다!
다음엔 이를 이용한 코딩 문제도 풀어보고자 한다.


고양이를 사랑하는 개발자의 블로그예요! 찾아주셔서 감사합니다 🤗

Update:

댓글남기기