백준_암호 만들기_1759

Minji Lee·2024년 9월 24일
0

JS코딩테스트

목록 보기
68/122

암호 만들기

문제

바로 어제 최백준 조교가 방 열쇠를 주머니에 넣은 채 깜빡하고 서울로 가 버리는 황당한 상황에 직면한 조교들은, 702호에 새로운 보안 시스템을 설치하기로 하였다. 이 보안 시스템은 열쇠가 아닌 암호로 동작하게 되어 있는 시스템이다.

암호는 서로 다른 L개의 알파벳 소문자들로 구성되며 최소 한 개의 모음(a, e, i, o, u)과 최소 두 개의 자음으로 구성되어 있다고 알려져 있다. 또한 정렬된 문자열을 선호하는 조교들의 성향으로 미루어 보아 암호를 이루는 알파벳이 암호에서 증가하는 순서로 배열되었을 것이라고 추측된다. 즉, abc는 가능성이 있는 암호이지만 bac는 그렇지 않다.

새 보안 시스템에서 조교들이 암호로 사용했을 법한 문자의 종류는 C가지가 있다고 한다. 이 알파벳을 입수한 민식, 영식 형제는 조교들의 방에 침투하기 위해 암호를 추측해 보려고 한다. C개의 문자들이 모두 주어졌을 때, 가능성 있는 암호들을 모두 구하는 프로그램을 작성하시오.

입력

첫째 줄에 두 정수 L, C가 주어진다. (3 ≤ L ≤ C ≤ 15) 다음 줄에는 C개의 문자들이 공백으로 구분되어 주어진다. 주어지는 문자들은 알파벳 소문자이며, 중복되는 것은 없다.

출력

각 줄에 하나씩, 사전식으로 가능성 있는 암호를 모두 출력한다.

예제 입력

4 6
a t c i s w

예제 출력

acis
acit
aciw
acst
acsw
actw
aist
aisw
aitw
astw
cist
cisw
citw
istw

Code

const fs = require('fs');
const input = fs.readFileSync('/dev/stdin').toString().split('\n');

const [L, C] = input[0].split(' ').map(Number);
let mo = []; // 모음
let ja = []; // 자음

input[1].split(' ').forEach((item) => {
  // 모음 분리
  if (['a', 'e', 'i', 'o', 'u'].includes(item)) mo.push(item);
  else ja.push(item); // 자음 분리
});

// 조합 함수
const getCombination = (arr, num) => {
  const results = []; // 조합 결과
  if (num === 1) return arr.map((a) => [a]);

  arr.forEach((fixed, index, origin) => {
    const rest = origin.slice(index + 1);
    const combinations = getCombination(rest, num - 1);
    const attached = combinations.map((el) => [fixed, ...el]);
    results.push(...attached);
  });
  return results;
};

const secretKeys = new Set(); // 중복 제거를 위해 집합 이용
let moCombi = getCombination(mo, 1); // 모음 1개 선택
let jaCombi = getCombination(ja, 2); // 자음 2개 선택

moCombi.map((mc) => {
  jaCombi.map((jc) => {
    let rest = []; // 선택된 모음 1개랑 자음 2개 제외한 나머지 값들
    rest.push(...mo.filter((m) => !mc.includes(m)));
    rest.push(...ja.filter((a) => !jc.includes(a)));
    let restCombi = getCombination(rest, L - 3); // 모음 1개, 자음 2개 선택 후 나머지 중 선택

    // 자음 2개 모음 1개로 L개 다 만들어졌을 때는 나머지 값 조합 X
    if (restCombi.length === 0) secretKeys.add([...mc, ...jc].sort().join(''));

    restCombi.map((rc) => {
      // 모음, 자음, 나머지 정렬 후 문자열로 만들기
      secretKeys.add([...mc, ...jc, ...rc].sort().join(''));
    });
  });
});

// 출력도 문자 순으로
[...secretKeys].sort().forEach((item) => console.log(item));

풀이 및 해설

  • 구하고자 하는 것 ⇒ 가능성 있는 새로운 보안 시스템의 암호들

    • 새로운 보안 시스템 조건
      • 서로 다른 L개의 소문자들로 구성
      • 최소 1개의 모음(a, e, i, o, u) + 최소 2개의 자음으로 구성 ⇒ 모음 1개랑 자음 2개는 무조건 존재해야함
      • 암호는 정렬 오름차순으로 배열
      • 문자의 종류가 C가지 존재
  • 풀이

    1. 모음과 자음 분리하여 입력 받기

    2. 조합 함수 이용해 모음 1개, 자음 2개 추출

    3. 추출된 모음/자음 제외한 나머지 값 중 L-3개 뽑기

      이때, 나머지를 뽑지 않아도 되는 경우 고려해서 if문으로 나머지 조합 길이가 0인 경우, 뽑은 모음과 자음으로 암호 만들기 (96%에서 틀림이 나온 원인)

    4. 사전순 정렬 후 문자열로 만들어 집합에 넣기

      ⇒ 중복 제거를 위해 집합 이용

    5. 출력도 사전순으로 정렬

0개의 댓글