백준 9046번 Node.js(자바스크립트) 풀이
❓ 문제
암호학에서 치환 암호(substitution cipher)란, 평문에 들어있는 각각의 문자를 주어진 치환 방법으로 암호화하는 방법 중 하나다.
가장 단순한 방법은 평문의 알파벳을 암호문의 알파벳으로 대치시켜 치환시키는 것이다.
예를 들어, 아래와 같은 알파벳 대치표가 주어졌다고 하자.
- 평문 알파벳 대치표 : abcdefghijklmnopqrstuvwxyz
- 암호문 알파벳 대치표 : wghuvijxpqrstacdebfklmnoyz
위에 주어진 치환 방법을 통해 암호화하면 평문 "hello there"은 "xvssc kxvbv"가 된다.
한 가지 흥미로운 점은 영어 문법 특성상, 알파벳 'e'가 다른 영문 알파벳에 비해 자주 쓰인다는 것이다.
즉, 암호문 알파벳 대치표 없이 암호문을 복호화하려 할 때, 암호문 알파벳 빈도수를 체크하면 암호문 알파벳 빈도수 중 가장 빈번하게 나타나는 알파벳이 'e'라는 사실을 유추해볼 수 있다.
위 방법으로 암호문 알파벳의 빈도수를 체크하고, 가장 빈번하게 나타나는 문자를 출력하는 프로그램을 작성하면 된다.
만약 주어진 암호문에서 가장 빈번하게 나타나는 문자가 여러 개일 경우, 그 빈번한 문자 중 어느 것이 평문 알파벳 'e'를 가리키는지 확실하게 알 수 없기 때문에 "모르겠음"을 의미하는 '?'를 출력하면 된다.
💻 입력
입력의 T(1 ≤ T ≤ 20)는 테스트 케이스로, 입력 제일 상단에 주어진다. 각각의 테스트 케이스는 한 줄마다 소문자와 공백으로 이루어진 영어 문장이 주어진다. 이 문장의 길이는 적어도 1이상이며 255이하다.
📈 출력
각각의 테스트 케이스에 대해, 가장 빈번하게 나타나는 문자를 출력하거나 빈번하게 나타나는 문자가 여러 개일 경우 '?'를 출력한다.
👩🏻 내가 제출한 코드
const input = require("fs").readFileSync("/dev/stdin").toString().trim().split("\n");
const T = parseInt(input[0]); // 첫 줄에서 테스트 케이스 수 T를 추출
for (let i = 1; i <= T; i++) { // 각 테스트 케이스별로 반복
const line = input[i];
const frequency = {};
let maxFreq = 0;
let result = [];
for (let char of line) {
if (char !== ' ') { // 공백 문자 제외
frequency[char] = (frequency[char] || 0) + 1;
if (frequency[char] > maxFreq) {
maxFreq = frequency[char];
result = [char]; // 최고 빈도수를 가진 새 문자로 결과 배열을 초기화
} else if (frequency[char] === maxFreq && !result.includes(char)) {
result.push(char); // 동일한 최고 빈도수를 가진 다른 문자 추가
}
}
}
console.log(result.length > 1 ? '?' : result[0]); // 결과 출력
}
👩🏻💻 풀이
const input = require("fs").readFileSync("/dev/stdin").toString().trim().split("\n");
>> 여기서 input은 여러 줄로 이루어진 문자열을 배열로 분할한 것
>> 파일 내용을 읽어 문자열로 변환하고, 문자열을 처리하여 배열로 변환
>> toString() : readFileSync() 함수는 기본적으로 파일의 내용을 Buffer 객체로 반환. Buffer 객체는 바이너리 데이터를 나타내며, 이를 사람이 읽을 수 있는 문자열로 변환하기 위해 toString() 메소드를 사용
>> trim() : 변환된 문자열에서 불필요한 앞뒤 공백이나 줄바꿈 문자를 제거
>> split("\n") : 줄바꿈 문자(\n)를 기준으로 분할하여 배열로 만듬
const T = parseInt(input[0]);
>> 첫 줄에서 테스트 케이스 수 T를 추출
>> 문제에서 "입력의 T(1 ≤ T ≤ 20)는 테스트 케이스로, 입력 제일 상단에 주어진다."라고 했기때문에 input[0]에서
테이스 케이스 수 T를 추출하는 것이다.
>> parseInt : string을 정수로 변환한 값을 리턴
for (let i = 1; i <= T; i++) { // 각 테스트 케이스별로 반복
const line = input[i]; //input 배열 각각의 값을 line에 저장
const frequency = {}; //문자별 빈도수를 저장할 객체
let maxFreq = 0; //가장 높은 빈도수를 저장할 변수
let result = []; //가장 비번한 문자들을 저장할 배열
for (let char of line) {
if (char !== ' ') { // 공백 문자 제외
frequency[char] = (frequency[char] || 0) + 1;
if (frequency[char] > maxFreq) {
maxFreq = frequency[char];
result = [char]; // 최고 빈도수를 가진 새 문자로 결과 배열을 초기화
} else if (frequency[char] === maxFreq && !result.includes(char)) {
result.push(char); // 동일한 최고 빈도수를 가진 다른 문자 추가
}
}
}
console.log(result.length > 1 ? '?' : result[0]); // 결과 출력
}
↓↓↓↓↓↓↓↓
for (let char of line) {
>> for...of : 반복문은 반복 가능한 객체(예: 배열, 문자열, Map, Set 등)를 통해 반복을 수행할 때 사용, 객체의 각 요소를 순서대로 처리할 때 유용하다.
frequency[char] = (frequency[char] || 0) + 1;
>> (frequency[char] || 0) : frequency[char]에 값이 없으면 0, 값이 있으면 frequency[char]의 값을 사용
else if (frequency[char] === maxFreq && !result.includes(char)) {
result.push(char); // 동일한 최고 빈도수를 가진 다른 문자 추가
}
>> frequency[char] === maxFreq : 이 조건은 현재 문자 char의 빈도(frequency[char])가 현재까지 알려진 최고 빈도(maxFreq)와 같은지를 검사. 이는 새로운 문자가 발견될 때마다 그 문자의 빈도가 최고 빈도와 같은지를 확인하여, 최고 빈도를 공유하는 모든 문자를 추적할 수 있게 한다.
>> !result.includes(char): 이 조건은 결과 배열 result에 현재 문자 char가 이미 포함되어 있는지를 확인. result.includes(char)는 문자가 배열에 존재하면 true를 반환하므로, !result.includes(char)는 그 문자가 아직 결과 배열에 없을 때 true가 됨. 이를 통해 동일 문자를 중복하여 결과 목록에 추가하는 것을 방지.
>> 한마디로 여기 조건은 char의 빈도(frequency[char])가 현재까지 알려진 최고 빈도(maxFreq)와 같고 배열 result에 현재 문자 char가 없으면 true!
🔗문제 링크
https://www.acmicpc.net/problem/9046
'Coding With Jina > Coding Test' 카테고리의 다른 글
[코딩테스트] 백준 1157번 Node.js(자바스크립트) 풀이 (0) | 2024.04.23 |
---|---|
[코딩테스트] 백준 11720번 Node.js(자바스크립트) 풀이 (0) | 2024.04.23 |
[코딩테스트] 백준 2558번 Node.js(자바스크립트) 풀이 (0) | 2024.04.21 |
[정리] 백준에서 자바스크립트로 문제 푸는 방법 (0) | 2024.04.18 |
[코딩테스트] 백준 1000번 Node.js(자바스크립트) 풀이 (0) | 2024.04.16 |