본문 바로가기

Algorithm/99클럽

[99클럽] 코딩테스트 스터디, 5일차 "모스부호" TIL - 비기너 (feat. 백준에서 자바스크립트 사용하기)

728x90



1. 문제풀이

1) 문제, 모스 부호 (백준, 29701)

혜민이는 요즘 모스 부호에 관심이 많아졌다. 모스 부호는 짧은 신호와 긴 신호를 적절히 조합하여 문자 기호를 표기하는 방식이다. 각 문자를 나타내는 방식은 미리 정해져 있는데, 예를 들어, 짧은 신호를 '.', 긴 신호를 '-'로 나타낸다면, 모스 부호로 알파벳 'A'는 '.-', 숫자 1은 '.----'와 같이 표기할 수 있다. 모스 부호를 알고 있으면 위험한 상황에서 구조 요청을 하는 데 유용할 것 같아, 혜민이는 평상시에 친구들과 연락을 주고받을 때도 모스 부호를 사용하려고 한다. 혜민이는 친구들이 보내온 모스 부호를 올바르게 해독했는지 바로바로 확인하고 싶어졌다. 알파벳 A-Z, 숫자 0-9, 기호 ',', '.', '?', ':', '-', '@'로 이루어진 길이 N인 문자열을 변환한 모스 부호가 주어질 때, 주어진 모스 부호를 해독하여 원래의 문자열을 출력하는 프로그램을 작성해 보자.

 

각 문자를 모스 부호로 나타내는 방법은 아래 표에 정리되어 있다.

(단, 표의 둘째, 넷째 열은 첫째, 셋째 열의 문자를 모스 부호로 변환한 결과를 나타내며, '.'는 짧은 신호를, '-'는 긴 신호를 의미한다.)

 

 

입력

- 첫째 줄에 모스 부호로 변환하기 전 문자열의 길이를 나타내는 정수 N(1≤N≤100)이 주어진다.

- 둘째 줄에 원래의 문자열을 모스 부호로 변환한 메시지가 주어진다. 이 메시지에서 짧은 신호는 '.', 긴 신호는 '-'로 나타내며, 원래의 문자열을 구성하는 각각의 문자를 모스 부호로 변환한 결과는 공백으로 구분되어 있다.

- 위 표를 이용해 해독할 수 없는 메시지는 주어지지 않는다.

 

출력

- 주어진 모스 부호를 해독하여 길이 N인 문자열을 공백 없이 출력한다.

- 알파벳의 경우, 반드시 대문자로 출력한다.

 

2) 해석

 

- 모스부호가 주어지면 해독해서 원래의 문자열 출력
- 첫 번째 인수 : 모스부호 길이
- 두 번째 인수 : 모스부호 문자열 

- 문자열 배열로 변환한 후, for Each 돌리기
- 치환

 

3) 풀이

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

const morseCodeMap = {
  ".-": "A",
  "-...": "B",
  "-.-.": "C",
  "-..": "D",
  ".": "E",
  "..-.": "F",
  "--.": "G",
  "....": "H",
  "..": "I",
  ".---": "J",
  "-.-": "K",
  ".-..": "L",
  "--": "M",
  "-.": "N",
  "---": "O",
  ".--.": "P",
  "--.-": "Q",
  ".-.": "R",
  "...": "S",
  "-": "T",
  "..-": "U",
  "...-": "V",
  ".--": "W",
  "-..-": "X",
  "-.--": "Y",
  "--..": "Z",
  ".----": "1",
  "..---": "2",
  "...--": "3",
  "....-": "4",
  ".....": "5",
  "-....": "6",
  "--...": "7",
  "---..": "8",
  "----.": "9",
  "-----": "0",
  "--..--": ",",
  ".-.-.-": ".",
  "..--..": "?",
  "---...": ":",
  "-....-": "-",
  ".--.-.": "@"
};

const morseCodeMessage = input[1];
const morseCodeArr = morseCodeMessage.split(" ");
let result = "";

morseCodeArr.forEach(code => result += morseCodeMap[code]);

console.log(result);

 

이번 문제는 어렵다기보단 모스 부호를 하나하나 입력하는게 힘들었다..

 

우선 모스 부호를 obj에 저장해준다.

그 후 입력받은 모스 부호를 반복문으로 돌려, obj에 있는 모스 부호를 찾아서 result에 넣어준다.

 

마지막으로 result를 출력해 주면 된다. 

 

 

 

- 걸린 시간

 

사실 푸는 시간은 얼마 안 걸렸는데, node.js 입력하는 게 처음이라 애먹었다ㅠ

 

 

 

2. 리팩토링

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

const morseCodeMap = {
  ".-": "A",
  "-...": "B",
  "-.-.": "C",
  "-..": "D",
  ".": "E",
  "..-.": "F",
  "--.": "G",
  "....": "H",
  "..": "I",
  ".---": "J",
  "-.-": "K",
  ".-..": "L",
  "--": "M",
  "-.": "N",
  "---": "O",
  ".--.": "P",
  "--.-": "Q",
  ".-.": "R",
  "...": "S",
  "-": "T",
  "..-": "U",
  "...-": "V",
  ".--": "W",
  "-..-": "X",
  "-.--": "Y",
  "--..": "Z",
  ".----": "1",
  "..---": "2",
  "...--": "3",
  "....-": "4",
  ".....": "5",
  "-....": "6",
  "--...": "7",
  "---..": "8",
  "----.": "9",
  "-----": "0",
  "--..--": ",",
  ".-.-.-": ".",
  "..--..": "?",
  "---...": ":",
  "-....-": "-",
  ".--.-.": "@"
};

const morseCodeMessage = input[1];

// map과 join을 사용하여 더 함수형 스타일로 리팩토링
const result = morseCodeMessage
  .split(" ")
  .map(code => morseCodeMap[code] || '') // map을 통해 각 코드를 변환
  .join(''); // 변환된 결과를 문자열로 합치기

console.log(result);

 

forEach를 사용하지 않고, map을 이용해 바로 변환해 줬다.

 

map의 경우 각 요소를 다른 값으로 변환할 때 사용하기 때문에 그 의도를 명확히 전달할 수 있다.

또한 가독성도 좋아진다. 

불필요한 변수도 하나 줄였다!

 

나도 모르게 for을 자꾸 사용하게 되는데, 다른 값으로 변환할 때는 map을 사용하는 습관을 들여야겠다.

 

3. 기타

1) 백준에서 자바스크립트로 문제 푸는 방법

백준에는 javascript가 없기 때문에 문제를 풀기 위해서는 node.js를 사용해야 한다.

 

원래는 사용방법이 복잡해서 백준은 사용 안 했었는데,

이번 코딩테스트 문제가 백준으로 나와서 써본 김에 하는 방법을 정리하려 한다!

 

 

①  fs 모듈

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

 

위 코드가 공식이라고 생각하면 된다.

 

fs 모듈은 파일을 읽어오는 모듈로, 괄호에 있는 파일을 읽어와 준다.

기본적으로 Buffer 객체를 반환하기 때문에 toString()으로 문자열로 전환해줘야 한다.

 

그 후, trim()으로 불필요한 공백이나 개행을 제거하고 split("\n")을 이용해 각 줄을 배열 요소로 분리해 준다.

 

 

3 4
Hello World
123 456 789

//["3 4", "Hello World", "123 456 789"]

 

위 텍스트를 입력받으면, 이렇게 배열로 출력된다.

 

 

const fs = require("fs");
const input = fs.readFileSync("index.txt").toString().trim().split("\n");

 

만일, vscode에서 실행하고 싶다면 따로 입력 파일을 만들고 readFileSync 괄호에 해당 파일 경로를 입력해 주면 된다.

그리고 "node 파일명"을 입력하면 실행된다.

 

 

 

② readlline 이용하기

 

간혹 백준에서 런타임 에러가 나는 경우가 있다.

그럴 땐 readline을 한 번 사용해 보자.

const readline = require("readline");

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

const input = [];

rl.on("line", (line) => {
  input.push(line);
});

rl.on("close", () => {
  // 모든 입력이 완료되었을 때 실행되는 부분
  // 문제 풀이 코드 작성
  // ...

  console.log(result); // 결과 출력
  process.exit();
});

 

fs 모듈과 달리 입력되는 값들을 readline을 통해 한 줄씩 읽어오는 온다.

입력과 출력을 따로 분리하여 작성하는 형태로 구성되어 있다.

 

readline 모듈을 통해 input, output을 설정해 준다.

rl.on("line")은 입력의 각 줄이 들어올 때마다 발생한다.

문자열 형태로 전달되며, input.push를 통해 나중에 전체 입력을 처리할 수 있도록 해준다.

 

rl.on("close")는 모든 입력이 끝났을 때 실행된다.

여기서 input을 이용해 데이터를 가공하고, 문제 풀이 코드를 작성하면 된다.

 

process.exit()는 코드를 종료해 준다는 의미이다.

728x90
반응형