문제
프로그래머스
SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
요구사항
어떤 문장의 각 알파벳을 일정한 거리만큼 밀어서 다른 알파벳으로 바꾸는 암호화 방식을 시저 암호라고 합니다. 예를 들어 "AB"는 1만큼 밀면 "BC"가 되고, 3만큼 밀면 "DE"가 됩니다. "z"는 1만큼 밀면 "a"가 됩니다. 문자열 s와 거리 n을 입력받아 s를 n만큼 민 암호문을 만드는 함수, solution을 완성해 보세요.
제한조건
- 공백은 아무리 밀어도 공백입니다.
- s는 알파벳 소문자, 대문자, 공백으로만 이루어져 있습니다.
- s의 길이는 8000이하입니다.
- n은 1 이상, 25이하인 자연수입니다.
입출력
s n result "AB" 1 "BC" "z" 1 "a" "a B z" 4 "e F d"
내가 생각한 로직과 구현한 코드
01
a부터 z까지 주어져 있지 않는데, 어떻게 AB가 BC가 되게 만드는지 방법을 전혀 모르겠었다.
그러다가 문득 알파벳을 숫자로 바꿀 수 있는 코드가 있지 않았나...?라는 생각이 들었다.
그게 바로 아스키 코드였다. 아스키 코드를 이용하면 되는건가 싶어서 이리저리 코드를 짜봤다.
function solution(s, n) {
const arr = [];
for(let i = 0; i < s.length; i++) {
arr.push(s.charCodeAt(i) + n);
}
return arr.map(s => String.fromCharCode(s)).join("");
}
1. 문자열 s의 알파벳 하나하나를 아스키 코드로 바꿔준 뒤, 각각을 n만큼 더한다.
2. 아스키 코드로 만들어진 배열을 다시 문자열로 변환한다.
🚨 예제 1번은 됐는데 예제 2번에서 막혔다. z를 밀면 다시 a가 되기 때문이다.
02
z에서 a가 되는 것을 보고 계산식이 필요하다는 것을 느꼈다.
z의 아스키 코드가 122라면 계산식을 통해 a의 아스키 코드로 돌아가야 된다.
알파벳 개수가 26개이기 때문에 26을 빼주고 n만큼 더해주면 처음으로 순회할 수 있을 거라고 생각하였다.
function solution(s, n) {
const arr = s.split("").map((s) => {
if (s.charCodeAt() === 122) {
return 122 - 26 + n
}
if (s === " ") {
return s.charCodeAt()
}
return s.charCodeAt() + n
});
return arr.map(s => {
return String.fromCharCode(s)
}).join("");
}
1. split와 map을 이용해서 n만큼 더해진 아스키 코드 배열을 만든다.
2. 조건식을 통해 아스키 코드가 122(z)라면 a로 돌아가게 만든다.
3. 조건식을 통해 s가 공백이라면 아스키 코드를 그대로 반환한다.
4. map을 통해 다시 아스키 코드를 문자열로 변환한다.
🚨 예제 1, 2, 3은 모두 통과했지만...
테스트를 아무것도 통과하지 못하였다.
도대체 무엇이 문제일까...?
이미 1시간을 소요한 상태였기 때문에 chatGPT에게 내 코드의 문제점이 무엇인지 물어봤다.
대문자 Z를 고려하지 않은 식이라고 하였다.
예제에 나와있는 소문자 z만 고려하고 대문자를 생각하지 않은 채 식을 짰던 것이었다.
✅ 대문자의 아스키 코드와 소문자의 아스키 코드를 모두 고려한 코드를 짜야 한다.
function solution(str, n) {
return str.split("").map((s) => {
if (s === " ") return " ";
let code = s.charCodeAt();
let isUpperCase = code >= 65 && code <= 90;
let isLowerCase = code >= 97 && code <= 122;
if (isUpperCase) {
return String.fromCharCode(((code - 65 + n) % 26) + 65);
}
if (isLowerCase) {
return String.fromCharCode(((code - 97 + n) % 26) + 97);
}
return s;
}).join("");
}
아스키 코드 범위를 이용해서 대문자와 소문자를 따로 처리해준다.
return String.fromCharCode(((code - 65 + n) % 26) + 65);
return String.fromCharCode(((code - 97 + n) % 26) + 97);
a부터 z까지 순회하기 위한 코드이다.
65 = A의 아스키 코드
97 = a의 아스키 코드
- code에서 65와 97을 빼주는 이유는 a로부터의 상대적인 위치를 구하기 위해서이다.
- 26으로 나눴을 때의 나머지를 구하는 것을 통해 a로 다시 돌아갈 수 있게 해준다.
⭐️ 문제를 풀면서 느낀 점
단순히 메서드 사용 방법만 안다고 해서 알고리즘 문제를 풀 수 있는 건 아니었다.
패턴을 발견하고 그것을 코드로 변환할 수 있어야 했다.
이번 문제로 예를 들면, a부터 z까지의 범위 내에서 순회하기 위한 패턴을 발견해야 한다.
알파펫은 26개이기 때문에 % 연산자를 통해 범위를 벗어나도 다시 처음으로 돌아오게 만들 수 있었다.
비슷한 유형의 문제를 풀어보면서 패턴에 익숙해질 필요도 있는 것 같다.
✅ 이번 문제에서 배운 패턴
· 정해진 범위가 있고, 그 범위 내에서 순회하려고 한다면 범위만큼 나눠줬을 때의 나머지 값을 이용한다.
다른 해결방법
function caesar(s, n) {
var result = "";
// 함수를 완성하세요.
var alphabetArray = ["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",
"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",
"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",
"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",
"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",
"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",
"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",
"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",
" "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," ",
" "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," ",
" "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," ",
" "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," ",];
var splitArray = s.split("");
//indexOf 로 배열에서 인덱스를 알아낸 후 인덱스에 n을 더한다.
for(var i = 0 ; i < splitArray.length ; i++)
{
var mn = alphabetArray.indexOf(splitArray[i]);
splitArray[i] = alphabetArray[mn+n];
result = result + "" + splitArray[i];
}
return result;
}
알파벳을 배열로 만든 사람을 보고 엄청난 광기를 느꼈다.
var upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var lower = "abcdefghijklmnopqrstuvwxyz";
var answer= '';
for(var i =0; i <s.length; i++){
var text = s[i];
if(text == ' ') {
answer += ' ';
continue;
}
var textArr = upper.includes(text) ? upper : lower;
var index = textArr.indexOf(text)+n;
if(index >= textArr.length) index -= textArr.length;
answer += textArr[index];
}
return answer;
}
아스키 코드를 사용하지 않고도 코드를 작성할 수 있었다.
차라리 알파벳을 내가 만들어서 코드에서 사용하는게 더 쉬울 수 있었겠다라는 생각이 들었다.
'Algorithm > 프로그래머스 LV1' 카테고리의 다른 글
[프로그래머스] 기사단원의 무기 (Javascript) (1) | 2025.05.30 |
---|---|
[프로그래머스] 가장 가까운 같은 글자 (Javascript) (0) | 2025.02.13 |
[프로그래머스] 최소직사각형 (Javascript) (0) | 2025.02.10 |
[프로그래머스] 삼총사 (Javascript) (1) | 2025.02.07 |
[프로그래머스] 3진법 뒤집기 (Javascript) (0) | 2025.02.06 |