조합과 순열


코딩 테스트 문제를 풀다 보면 이런 문장을 만나게 됩니다.

“ 순서를 고려한 경우의 수를 구하시오.” ” 순서에 상관없이 고를 수 있는 방법의 수는?”

이런 말이 나오면 순열 혹은 조합을 떠올려야 합니다. 그렇다면 어떤 상황에서 조합을 쓰고, 언제 순열을 써야 할까요?

순열(Permutation) 알고리즘 = 선택 + 나열

순열이란 여러 개 중에서 일부를 골라서 줄 세우는 경우의 수 입니다. 즉, 순서까지 중요한 경우로 순서가 다르면 다른 경우로 셉니다.

오늘 풀게되는 문제와 같이, A, B 스킬로 공격을 하는 경우 AB로 하는 공격과 BA로 하는 공격은 분명히 다른 경우입니다. 즉, 순서가 다르면 다른 경우로 보는 것을 순열이라고 합니다.

function getPermutations(arr, selectNum) {
  const result = [];

  // 베이스 케이스: 1개만 뽑는다면 → 각 원소 자체가 하나의 순열
  if (selectNum === 1) return arr.map(v => [v]);

  // 배열의 각 원소를 하나씩 고정(fixed)해서 시작
  arr.forEach((fixed, idx, origin) => {
    // 현재 고른 원소를 제외한 나머지를 rest로 만든다
    const rest = [...origin.slice(0, idx), ...origin.slice(idx + 1)];

    // 나머지 원소들에서 (selectNum - 1)개를 뽑아 순열 생성 (재귀)
    const perms = getPermutations(rest, selectNum - 1);

    // 앞에 고정된 원소를 붙여서 전체 순열 만들기
    const attached = perms.map(p => [fixed, ...p]);

    // 결과에 추가
    result.push(...attached);
  });

  return result;
}
getPermutations(['A', 'B', 'C'], 2); 
// [['A', 'B'], ['A', 'C'], ['B', 'A'], ['B', 'C'], ['C', 'A'], ['C', 'B']]

👉🏻 순열 코딩테스트 문제

BOJ 10974번 - 모든 순열

조합(Combination) 알고리즘 = 선택

조합이란 여러 개 중에서 일부를 골라만보는 경우의 수 입니다. 즉, 순서는 중요하지 않습니다.

가장 쉬운 예가 로또 번호입니다. 로또 번호를 추첨할 때 숫자의 순서와 상관없이 6개의 숫자를 뽑습니다. 12, 4, 30, 31, 7, 5 이든, 4, 5, 7, 12, 30, 31이든 순서는 중요하지 않습니다.

function getCombinations(arr, selectNum) {
  const result = [];

  // 베이스 케이스: 1개만 뽑는다면 → 각 원소 자체가 하나의 조합
  if (selectNum === 1) return arr.map(v => [v]);

  arr.forEach((fixed, idx, origin) => {
    // 조합은 중복을 방지해야 하므로, 현재 원소 이후만 고려
    const rest = origin.slice(idx + 1);

    // 나머지 원소들에서 (selectNum - 1)개를 뽑아 조합 생성 (재귀)
    const combs = getCombinations(rest, selectNum - 1);

    // 고정된 원소를 앞에 붙여서 전체 조합 만들기
    const attached = combs.map(c => [fixed, ...c]);

    // 결과에 추가
    result.push(...attached);
  });

  return result;
}
getCombinations(['A', 'B', 'C'], 2);
// [['A', 'B'], ['A', 'C'], ['B', 'C']]

👉🏻 조합 코딩테스트 문제

BOJ 6603번 - 로또

BOJ 1759번 - 암호 만들기