일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 리트코드
- RN 프로젝트
- 부트캠프
- 프론트개발공부
- 삼항연산자
- JavaScript
- 자바스크립트 날씨 웹 만들기
- 프로그래머스
- [파이썬 실습] 기초 문제
- 자바스크립트 sort()
- 개발일기
- 코드스테이츠
- 프론트개발
- [파이썬 실습] 중급 문제
- 엘리스 ai 트랙
- 자바스크립트
- HTML
- [파이썬 실습] 심화 문제
- 날씨 웹 만들기
- 개발공부
- 코딩부트캠프
- [AI 5기] 연습 문제집
- 자바스크립트 reduce()
- 자바스크립트 split()
- 엘리스 AI 트랙 5기
- 엘리스
- 간단한 날씨 웹 만들기
- reactnativecli
- 자바스크립트 날씨
- leetcode
- Today
- Total
개발조각
[프로그래머스] 시저 암호 본문
이번 문제는 어려운 편은 아닌데 묘하게 조건이 헷갈려서 헤맸던 문제인 것 같아요.


해결방안 설명하기 전에 이 문제는 주의해야 될 점이 꽤 있어서 주의 사항부터 설명하겠습니다.
주의 사항
- "z"는 1만큼 밀면 "a"가 됩니다.
제한 조건
- 공백은 아무리 밀어도 공백입니다.
- s는 알파벳 소문자, 대문자, 공백으로만 이루어져 있습니다. -> 알파벳 소문자, 대문자, 공백만 비교하면 됨
- n은 1 이상, 25이하인 자연수입니다. -> n이 25일 경우도 생각해봐야 됨
이 4가지 사항을 주의하면서 코드를 풀어야 됩니다.
입출력 예에서 웬만한 조건에 대해서는 잘 설명이 되어 있는데요.
여기서 또 생각해 봐야 되는 부분이 있습니다.
만약 s = "CD"; n=25;이면 어떻게 될까요?
답 : s="BC"
이렇게 됩니다.
그러므로 단순히 n만큼 밀때만 생각하는 것이 아니라
문자열s의 문자에 n만큼 밀 때 z이후일 경우에도 생각해봐야 됩니다.
이 경우도 생각하시고 풀어야 제출 후 채점하기에서 정확성 테스트에 통과하게 됩니다.
해결방안
function solution(s, n) {
let upper =`ABCDEFGHIJKLMNOPQRSTUVWXYZ`;
let lower = `abcdefghijklmnopqrstuvwxyz`;
var answer = '';
for(let i = 0; i<s.length; i++){
let uppIdx = upper.indexOf(s[i]);
let lowIdx = lower.indexOf(s[i]);
if(s[i] === ' ')answer += ' ';
else if(uppIdx !== -1){
uppIdx+n > 25 ? answer += upper[uppIdx-26+n] : answer += upper[uppIdx+n];
}else{
lowIdx+n > 25 ? answer += lower[lowIdx-26+n] : answer += lower[lowIdx+n];
}
}
return answer;
}
해결방안 순서
- 대문자 A~Z까지 upper에 문자열로 담기, 소문자 a~z까지 lower에 문자열로 담기
- for문, 조건문을 사용해서 시저 암호 작동되게 만들기
1단계. 대문자 A~Z까지 upper에 문자열로 담기, 소문자 a~z까지 lower에 문자열로 담기
let upper =`ABCDEFGHIJKLMNOPQRSTUVWXYZ`;
let lower = `abcdefghijklmnopqrstuvwxyz`;
var answer = '';
- let upper =`ABCDEFGHIJKLMNOPQRSTUVWXYZ`; : 대문자 A~Z까지 담음
- let lower = `abcdefghijklmnopqrstuvwxyz`; : 소문자 a~z까지 담음
- var answer = ''; s문자열에 시저 암호를 적용한 값을 담아줄 문자열 변수
먼저 대소문자를 각각 문자열로 담았습니다.
문자열 s에는 대소문자가 섞여있기 때문에 대문자, 소문자를 따로 비교하기 위해 담아주었습니다.
여기서 upper, lower변수를 배열이 아닌 문자열까지만 쓴 이유는
upper[3] = "D"
이렇게 문자열에서도 배열처럼 index를 적용할 수 있기 때문에 배열을 쓸 필요가 없어 문자열로 썼습니다.
2단계. for문, 조건문을 사용해서 시저 암호 작동되게 만들기
for(let i = 0; i<s.length; i++){
let uppIdx = upper.indexOf(s[i]);
let lowIdx = lower.indexOf(s[i]);
if(s[i] === ' ')answer += ' ';
else if(uppIdx !== -1){
uppIdx+n > 25 ? answer += upper[uppIdx-26+n] : answer += upper[uppIdx+n];
}else{
lowIdx+n > 25 ? answer += lower[lowIdx-26+n] : answer += lower[lowIdx+n];
}
}
return answer;
이 코드 부터는 시저 암호를 적용되게 만드는 코드입니다.
먼저 for문을 돌려 문자열s의 각각의 문자를 순서대로 제어할 수 있게 했습니다.
이점을 이용해서 조건문으로
- 문자가 공백일 경우 공백으로
- 문자가 대문자일 경우 대문자에서 n만큼 밀어주기
- 문자가 소문자일 경우 소문자에서 n만큼 밀어주기
이런 식으로 구해주었습니다.
여기서 문자가 대문자와 소문자일 경우
s문자열의 문자에 n만큼 밀 때 z보다 클경우에 대해서도 조건문으로 제어해 주었습니다.
for(let i = 0; i<s.length; i++)
for문을 사용하여 문자열s의 각각의 문자를 순서대로 제어할 수 있게 했습니다.
테스트 1 (s = "AB"; n=1;)
for(let i = 0; i<s.length; i++)
-> s.length = 2
-> 0, 1 두번 반복
테스트 2 (s = "z"; n=1;)
for(let i = 0; i<s.length; i++)
-> s.length = 1
-> 0 한번 반복
테스트 3 (s = "a B z"; n=4;)
for(let i = 0; i<s.length; i++)
-> s.length = 5
-> 0, 1, 2, 3, 4 다섯번 반복
let uppIdx = upper.indexOf(s[i]);
let lowIdx = lower.indexOf(s[i]);
- let uppIdx = upper.indexOf(s[i]); : 문자열s의 i번째 문자가 upper(대문자문자열)에서 몇번째 문자인지 찾기
- let lowIdx = lower.indexOf(s[i]); : 문자열s의 i번째 문자가 lower(소문자문자열)에서 몇번째 문자인지 찾기
uppIdx, lowIdx변수를 만들어준 이유는
- 깔끔하게 정리하기 위해서
- 대문자, 소문자, 공백을 구분하기 위해
- 위에 두 변수를 활용해서 아래 코드에 있는 조건문에 사용하기 위해
- indexOf(s[i]);을 넣어주어 s문자열의 i번째 문자가 upper, lower문자열에 몇 번째 위치에 있는지 찾도록 하기 위해
이러한 이유로 uppIdx, lowIdx변수를 만들어 주었습니다.
indexOf메서드에 대해서는 전에 "[프로그래머스] 문자열 내 p와 y의 개수"에서도 소개했는데요.
궁금하시면 아래 링크에서 확인하면 됩니다.👇
https://development-piece.tistory.com/20
[프로그래머스] 문자열 내 p와 y의 개수
이번 문제는 쉬운 편에 속하는 것 같아요. 프로그래머스에서 반복문은 항상 for문만 썼는데 이번에는 while문을 써서 풀어보았고 함수로 담는게 더 깔끔한 것 같아서 함수를 만들어보았습니다. 해
development-piece.tistory.com
그렇지만 보기 귀찮을 것 같아서 또 설명하겠습니다.
MDN Web Docs
String.prototype.indexOf()
indexOf() 메서드는 호출한 String 객체에서 주어진 값과 일치하는 첫 번째 인덱스를 반환합니다. 일치하는 값이 없으면 -1을 반환합니다.
구문 : str.indexOf(searchValue[, fromIndex])
- searchValue :찾으려는 문자열. 아무 값도 주어지지 않으면 문자열 "undefined"를 찾으려는 문자열로 사용합니다.
- fromIndex Optional : 문자열에서 찾기 시작하는 위치를 나타내는 인덱스 값입니다. 어떤 정수 값이라도 가능합니다. 기본값은 0이며, 문자열 전체를 대상으로 찾게 됩니다. 만약 fromIndex 값이 음의 정수이면 전체 문자열을 찾게 됩니다. 만약 fromIndex >= str.length 이면, 검색하지 않고 바로 -1을 반환합니다. searchValue가 공백 문자열이 아니라면, str.length를 반환합니다.
// String.prototype.indexOf() 예제
const s = "ppoooy"
console.log(s.indexOf("p")); // 0
console.log(s.indexOf("o")); // 2
console.log(s.indexOf("y")); // 5
console.log(s.indexOf("p", 1)); // 1
console.log(s.indexOf("p", 2)); // -1
여기서 중요한 점은 "일치하는 값이 없으면 -1을 반환합니다."는 점입니다.
"프로그래머스 문자열 내 p와 y의 개수"를 풀 때도 이점을 활용했었는데, 이번에도 -1이라는 점을 사용할 예정입니다.
s[i]가 공백이면
- uppIdx = -1
- lowIdx = -1
s[i]가 대문자이면
- uppIdx = -1이 아닌 숫자가 나옴
- lowIdx = -1
s[i]가 소문자이면
- uppIdx = -1
- lowIdx = -1이 아닌 숫자가 나옴
이런 식으로 s[i]가 공백, 대문자, 소문자일때마다 -1이 다르게 나옵니다.
그리고 s[i] 문자가 upper, lower배열에 몇 번째에 위치하는지도 확인할 수 있습니다.
let uppIdx = upper.indexOf(s[i]);
let lowIdx = lower.indexOf(s[i]);
테스트 1 (s = "AB"; n=1;)
i = 0일 때 : uppIdx = 0 , lowIdx = -1 -> 대문자, s[0] === upper[0]
i = 1일 때 : uppIdx = 1, lowIdx = -1 -> 대문자, s[1] === upper[1]
테스트 2 (s = "z"; n=1;)
i = 0일 때 : uppIdx = -1, lowIdx = 25 -> 소문자, s[0] === lower[25]
테스트 3 (s = "a B z"; n=4;)
i = 0일 때 : uppIdx = -1, lowIdx = 0 -> 소문자, s[0] === lower[0]
i = 1일 때 : uppIdx = -1, lowIdx = -1 -> 공백
i = 2일 때 : uppIdx = 1, lowIdx = -1 -> 대문자, s[1] === upper[1]
i = 3일 때 : uppIdx = -1, lowIdx = -1 -> 공백
i = 4일 때 : uppIdx = -1, lowIdx = 25 -> 소문자, s[4] === lower[25]
이점을 사용해서 다음코드 조건문에 적용해보겠습니다.
if(s[i] === ' ')
else if(uppIdx !== -1)
else
- if(s[i] === ' ') -> s[i] 공백일 경우
- else if(uppIdx !== -1) -> s[i] 대문자일 경우
- else -> s[i] 소문자일 경우
위에 설명에서 만든 uppIdx, lowIdex를 활용하여 조건문을 만들어 주었습니다.
- 공백은 s[i] === ' '만 해줘도 s[i]가 공백인지 아닌지 구분할 수 있어서 s[i] === ' ' 썼습니다.
- 대문자는 앞에서 uppIdx가 -1이 아니면 대문자라고 했습니다. 그래서 uppIdx === -1 썼습니다.
- 제한사항에서 "s는 알파벳 소문자, 대문자, 공백으로만 이루어져 있습니다."라고 했습니다. 그래서 위에 if, else if에서 공백, 대문자에 대한 처리를 해주었기 때문에 else만 썼습니다.
공백일 때 : answer += ' ';
공백은 제한 조건에서 "공백은 아무리 밀어도 공백입니다."이라고 했기 때문에 answer += ' ';을 써주었습니다.
대문자일 때 : uppIdx+n > 25 ? answer += upper[uppIdx-26+n] : answer += upper[uppIdx+n];
소문자 일 때 : lowIdx+n > 25 ? answer += lower[lowIdx-26+n] : answer += lower[lowIdx+n];
대문자와 소문자일 때는 단순히 n만큼 밀어주면 끝나는 것이 아니라
주의사항에서 말했던 대로 "문자열s의 문자에 n만큼 밀 때 z이후일 경우"도 생각해서 조건문을 써주어야 됩니다.
저는 한눈에 보기 쉽게 삼항 연산자를 사용해 주었습니다.
삼항 연산자
구문 : 조건 ? true : false
- 조건이 true이면 true를 실행
- 조건이 false이면 false를 실행
설명할 때는 대문자 위주로만 설명하겠습니다.
(소문자는 대문자에서 변수만 바꿔주면 되기 때문에 소문자에 대한 설명은 안 하겠습니다.)
조건 : uppIdx+n > 25
- uppIdx+n > 25 : 문자열s의 문자에 n만큼 밀때 Z이후일 경우
- uppIdx+n : Z이상일 경우
그리고 uppIdx+n이 25보다 커야 Z다음에 다시 A부터 문자를 받을 수 있습니다.
- 문자 = 'Y' -> uppIdx = 24, n=1 -> uppIdx+n =25 -> upper[25] -> z
- 문자 = 'Z' -> uppIdx = 25, n=1 -> uppIdx+n =26 -> upper[26] -> a
참 : answer += upper[uppIdx-26+n]
"문자열s의 문자에 n만큼 밀 때 z이후일 경우"가 참일 경우 Z다음 다시 A부터 세어서 알파벳을 반환해 주어야 됩니다.
- uppIdx-26+n = uppIdx-25+n -1
오른쪽에 있는 답을 합쳐서 왼쪽식으로 썼습니다.
uppIdx-25+n -1
먼저 25를 빼준이후는 uppIdx+n이 25보다 크기 때문에 다시 처음으로 돌아가 개수를 세주기 위해 25를 빼주었습니다.
그다음 n만큼 밀어줘야 되기 때문에 더해 주었고요.
마지막으로 -1을 넣어준 이유는 Z에서 A로 갈 때 1이 밀린 거라 그 1을 빼준 겁니다.
거짓 : answer += upper[uppIdx+n];
"문자열s의 문자에 n만큼 밀때 z이후일 경우"가 아닐 경우는 n만큼 밀어주면 되기 때문에 +n을 넣어주었습니다.
테스트 1 (s = "AB"; n=1;)
i = 0일 때
uppIdx = 0 , lowIdx = -1 -> 대문자, s[0] === upper[0]
uppIdx+n > 25 -> 0+1 >25 -> false임으로 answer += answer += upper[uppIdx+n] 실행
answer += upper[0 + 1]; -> answer += upper[1]; -> "B"
i = 1일 때
uppIdx = 1, lowIdx = -1 -> 대문자, s[1] === upper[1]
uppIdx+n > 25 -> 1+1 >25 -> false임으로 answer += upper[uppIdx+n] 실행
answer += upper[1+1]; -> answer += upper[2]; -> "C"
answer ="BC"
테스트 2 (s = "z"; n=1;)
i = 0일 때
uppIdx = -1, lowIdx = 25 -> 소문자, s[0] === lower[25]
lowIdx+n > 25 -> 25+1 >25 -> true임으로 answer += lower[lowIdx-26+n] 실행
answer += lower[25-26+1] -> answer += lower[0] -> "a"
answer ="a"
테스트 3 (s = "a B z"; n=4;)
i = 0일 때
uppIdx = -1, lowIdx = 0 -> 소문자, s[0] === lower[0]
lowIdx+n > 25 -> 0+4 >25 -> false임으로 answer += lower[lowIdx+n] 실행
answer += lower[0+4] -> answer += lower[4] -> "e"
i = 1일 때
uppIdx = -1, lowIdx = -1 -> 공백 -> answer += ' ' 실행
i = 2일 때
uppIdx = 1, lowIdx = -1 -> 대문자, s[1] === upper[1]
uppIdx+n > 25 -> 1+4 >25 -> false임으로 answer += answer += upper[uppIdx+n] 실행
answer += upper[1 + 4]; -> answer += upper[5]; -> "F"
i = 3일 때
uppIdx = -1, lowIdx = -1 -> 공백 -> answer += ' '실행
i = 4일 때
uppIdx = -1, lowIdx = 25 -> 소문자, s[4] === lower[25]
lowIdx+n > 25 -> 25+4 >25 -> true임으로 answer += lower[lowIdx-26+n] 실행
answer += lower[25-26+4] -> answer += lower[3] -> "d"
answer = "e F d"
여기까지 프로그래머스 시저 암호 해결방안에 대해 설명해보았습니다.
'알고리즘🅰 > 프로그래머스' 카테고리의 다른 글
[프로그래머스] 이상한 문자 만들기 (0) | 2022.02.28 |
---|---|
[프로그래머스] 약수의 합 (0) | 2022.02.25 |
[프로그래머스] 문자열을 정수로 바꾸기 (0) | 2022.02.23 |
[프로그래머스] 수박수박수박수박수박수? (0) | 2022.02.23 |
[프로그래머스] 소수 찾기 (0) | 2022.02.23 |