티스토리 뷰

오랜만에 프로그래머스에서 코딩테스트를 연습해봤다.

레벨 1인데도 넘 어렵...

시저 암호 문제는 영어 대문자와 소문자가 들어오면 입력받은 숫자만큼 뒷 순서의 알파벳을 반환해주는 뭐 그런 문제였음. 자세한건 프로그래머스 참고하세용

 

아무튼 문제를 본 순간 아스키코드로 풀어야할 것 같은 늬낌이 와서 풀어봤음

 

우선 문제 풀이 전 자바스크립트에서 아스키코드 변환 법을 알아보쟙

 

■ 문자에서 ASCII 코드로 변환하는 법 | charCodeAt() 함수

// 문자.charCodeAt(아스키 코드로 변환 할 문자 index);
let convertString = "ABC";

console.log(convertString.charCodeAt(0));
// 출력: 65
console.log(convertString.charCodeAt(1));
// 출력: 66
console.log(convertString.charCodeAt(2));
// 출력: 67

charCodeAt 함수는 매개변수로 ASCII 코드로 변환할 문자의 인덱스를 받아와서 해당 문자(char)를 변환해주는 함수이다.

문자열을 한번에 바꿔주는건 찾을 수 없었다...

매개변수를 넣어 주지 않으면 기본 값은 0으로 세팅되어있어서 젤 첫번째 글자의 아스키코드가 나오게 된다.


■ ASCII 코드에서 문자로 변환하는 법 | String.fromCharCode() 함수

// String.fromCharCode(변환 할 ASCII 코드 번호);

console.log(String.fromCharCode(65));
//출력: A
console.log(String.fromCharCode(65, 66, 67));
//출력: ABC

반대의 경우는 편리하게 아스키코드 숫자만 넣어주면 문자열로 바로 반환이 되었다.

매개변수의 경우 그냥 숫자만 ,(쉼표)로 구분해서 넣어주면 된다. (배열 x)

 


■ 시저 암호 문제 풀이

 

해당 함수를 통해서 프로그래머스의 시저암호 문제를 풀어보았다.

풀이가 2가지인 이유는 처음에 풀었던 if()문 방식이 넘 지저분해서 switch case로 코드를 바꿔봤기 때문...

(근데 if문 쓰는게 더 시간 빨랐음 ㅠㅠ)

 

1. if문을 이용

function solution(s, n) {
    let ascii_a = "a".charCodeAt(0);
    let ascii_z = "z".charCodeAt(0);
    let ascii_A = "A".charCodeAt(0);
    let ascii_Z = "Z".charCodeAt(0);

    return s.split("").reduce((str, char) => {
        let ascii = char.charCodeAt(0);
        let convertString = "";

        if(ascii_a <= ascii && ascii <= ascii_z){
            ascii += n;
            if(ascii_z < ascii) ascii = 96 + (ascii - ascii_z);
            convertString = String.fromCharCode(ascii);
        }else if(ascii_A <= ascii && ascii <= ascii_Z){
            ascii += n;
            if(ascii_Z < ascii) ascii = 64 + (ascii - ascii_Z);
            convertString = String.fromCharCode(ascii);
        }else if(ascii === 32){
            convertString = " ";
        }

        str += convertString

        return str;
    }, "");
}

여기서 이렇게 변수를 굳이 생성한건 ascii코드 숫자만 써놓으면 보기는 깔끔해도 남들이 봤을 때 바로 이해하기 어려울 것 같아서... (클린 코딩을 하고싶은 코린이)

 

암튼 소문자 z가 4칸 이동되면 대문자나 다른 특수기호가 되는 것이 아니라 소문자의 4번째 순서인 d가 나와야해서 범위를 제한하기 위해서 만든 변수들이다.

 

입력받아온 문자열을 한 글자씩 잘라서 reduce 함수를 통해 반복문을 돌린다.

(* reduce가 map과 다른 점: 특정 변수를 생성해 연산 결과를 반환할 수 있다.)

 

그리고 잘라온 글자의 ascii 코드를 charCodeAt()함수를 통해 ascii변수에 저장해준다.

 

여기가 초큼 보기 어려운데....

 

현재 char의 ascii 코드가 소문자 a~z에 속한다면  첫 번째 if()를 탄다.

 1. ascii코드에 n을 더해준다.

 2. 만약에 n을 더한 ascii값이 소문자 z의 아스키코드보다 크다면 ascii코드 값을 재정의 해준다.

    2-1. z보다 숫자 몇이 더 큰지 계산해서 96(소문자 a 전에 있는 ascii코드 숫자)에 더해준다.

출처: https://www.ibm.com/docs/ko/sdse/6.4.0?topic=administering-ascii-characters-from-33-126

    소문자 a의 전 ascii코드가 96임..ㅎㅎ 만약 ascii - ascii_z 의 결과가 4라면

    96+4 = 100이고 ascii코드에서 100은 소문자 d를 의미한다.

3. 연산이 된 ascii코드를 String.fromCharCode()함수에 넣어준 다음 convertString변수에 넣어준다.

 

두번째 if문도 위와 동일한 느낌으로 char가 대문자일 때 진행되는 연산이다.

 

마지막 ascii === 32는 공백을 의미하는 ascii코드이다. 공백또한 연산해버리면 다른 문자가 나오기 때문에 현재 char가 공백이라면 그냥 빈 공백을 돌려준다.

 

convertString에 저장된 현재 값과 기존에 reduce에서 만들어준 문자열 변수 str에 더해준 다음 return해줌

 

받아온 글자 길이만큼 위의 연산을 반복한다....

설명이 거지같지만 ㅠㅠ 끝!!

소요 시간과 메모리는 위와 같다.


2. switch() case를 이용

function solution(s, n) {
    let ascii_z = "z".charCodeAt(0);
    let ascii_Z = "Z".charCodeAt(0);
    
    return s.split("").reduce((str, char) => {
        let ascii = char.charCodeAt(0);
        let asciiPlusN = ascii + n;
        
        switch(Math.round(ascii/10)){
            case 6: case 7: case 8: case 9: // 대문자
                ascii_Z < asciiPlusN ? asciiPlusN += 64 - ascii_Z : null;
                str += String.fromCharCode(asciiPlusN);
                break;
                
            case 10: case 11: case 12:  // 소문자
                ascii_z < asciiPlusN ? asciiPlusN += 96 - ascii_z: null;
                str += String.fromCharCode(asciiPlusN);
                break;
            
            default:
                str += " ";
        }
        return str;
    }, "");
    
}

얘도 위에꺼랑 비슷한 느낌이다. 내 눈에는 얘가 더 깔끔한데 속도는 느려서 아쉬웠다.

 

우선 ascii코드를 10으로 나눠준 다음 반올림을 해준다.

반올림을 해주는 이유는 대문자 Z의 아스키코드는 91이고, 소문자 a의 아스키코드는 98으로 버림이나 올림을 했을 때 9라는 숫자가 겹쳐서 대소문자를 구분하기 어려울 것 같아서 반올림을 해주기로 했다.

그렇담 Z일 때는 case 9가 되고, 소문자 a일 때는 case 10이 될 것이다.

 

공백은 default에서 처리하기로 했다. 이유는 문제에서 받아오는 문자에 알파벳 소문자와 대문자, 그리고 공백만 들어온다고 했기 때문이다! case에 해당하지 않으면 무조건 공백이라는 뜻이겠지.

 

연산 속도는 위와 같다. if문으로 했을 때와 비슷하지만 쪼오끔 더 느린 듯 하다.

 

아무튼 charCodeAt과 String.fromCharCode를 통해 시저암호를 풀어보았다.

다른 분들이 푼 풀이를 보고 똑똑한 사람이 정말 많다는 것을 새삼 느끼게 되었다....


※ 참고로 테스트케이스는 통과해도 제출 시 미통과 하시는 분들은 질문하기 페이지에서 다른 테스트 코드를 참고하시길

바란다. 나는 Z와 10을 넣었을 때 J가 나오는 테스트케이스를 추가해봤는데 안되길래 코드를 바꿨더니 통과됐음

 

반응형
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함