문제 설명
두 문자열 s와 skip, 그리고 자연수 index가 주어질 때, 다음 규칙에 따라 문자열을 만들려 합니다. 암호의 규칙은 다음과 같습니다.
- 문자열 s의 각 알파벳을 index 만큼 뒤의 알파벳으로 바꿔줍니다.
- index 만큼의 뒤의 알파벳이 z를 넘어갈 경우 다시 a로 돌아갑니다.
- skip에 있는 알파벳은 제외하고 건너뜁니다.
예를 들어 s="aukks", skip="wbqd", index=5일 때, a에서 5만큼 뒤에 있는 알파벳은 f지만 [b, c, d, e, f]에서 'b'와 'd'는 skip에 포함되므로 세지 않습니다. 따라서 'b', 'd'를 제외하고 'a'에서 5만큼 뒤에 있는 알파벳은 [c, e, f, g, h] 순서에 의해 'h'가 됩니다. 나머지 "ukks" 또한 위 규칙대로 바꾸면 "appy"가 되며 결과는 "happy"가 됩니다.
두 문자열 s와 skip, 그리고 자연수 index가 매개변수로 주어질 때 위 규칙대로 s를 변환한 결과를 return하도록 solution 함수를 완성해주세요.
제한사항
- 5<=s의 길이<=50
- 1<=skip의 길이<=10
- s와 skip은 알파벳 소문자로만 이루어져 있습니다.
- skip에 포함되는 알파벳은 s에 포함되지 않습니다.
- 1<=index<=20
입출력 예
s | skip | index | result | 설명 | ||
"aukks" | "wbqd" | 5 | "happy" | 본문 내용과 일치합니다. | ||
"vwxyz" | "a" | 1 | "wxyzb" | 추가한 테스트 케이스 | ||
"y" | "baz" | 1 | "c" | 추가한 테스트 케이스 |
문제 풀이
풀이 언어 : C++
#include <string>
#include <vector>
using namespace std;
// z를 넘어갔는지 확인하고 조정하는 함수
char adjust_to_lowerAZ(char ch)
{
if(ch<='z') // z를 넘어가지 않았다면
{
return ch; // 그대로 반환
}
else // z를 넘어갔다면
{
return (char)('a'+ch%'z'-1); // 조정하여 반환
}
}
string solution(string s, string skip, int index) {
string answer = "";
for(int i=0; i<s.length(); i++)
{
char letter=s[i]; // letter 초기화
// index까지 하나씩 이동
for(int j=0; j<index; j++)
{
// 의무 이동
letter++; // 한 칸 이동
letter=adjust_to_lowerAZ(letter); // z를 넘어갔으면 조정
// 스킵 이동
for(int k=0; k<skip.size(); k++)
{
// letter가 skip에 있는 문자 중 하나라면
if(letter==skip[k])
{
letter++; // 한 칸 이동
letter=adjust_to_lowerAZ(letter); // z를 넘어갔으면 조정
k=-1; // k 초기화(이동한 글자로 다시 skip 확인)
}
}
}
answer+=letter; // 최종 글자 추가
}
return answer;
}
당연히 s의 한 글자씩 얼마나 뒤로 밀어야 하는지 봐야하기 때문에 반복문을 이용해 s를 한글자씩 순회한다. 반복문을 시작하면서는 s[i]를 letter에 대입한다. letter은 현재 보고 있는 문자이다.
이제 번거로워보이지만 for문으로 index까지 한글자씩 천천히 밀어준다. for문 안에서 일어나는 이동은 두 가지가 있다. 먼저 index만큼 이동해야하는 의무이동이 있다. skip을 제외하고 생각해도 일단 index만큼은 밀어야 하기 때문에 조건 없이 반복문 한번 돌 때마다 한칸은 이동하여야 한다. letter을 다음 글자로 이동시키고 'z'를 넘어갔는지 확인하고 조정한다.
adjust_to_lowerAZ(char ch) 함수는 ch가 'z'를 넘어갔는지 확인하고 넘어갔다면 'a'부터 다시 시작하도록 조정한다. 만약 'z'를 넘어가지 않았다면 그대로 ch를 반환하고 만약 'z'를 넘어갔다면 나머지 연산자를 사용해 'z' 뒤로 넘어가는 부분들은 'a'부터 시작하여 다시 표현하도록 한다. 예를 들어 'z'가 한칸 벗어나 'z'+1상태라면 'z'로 나눈 나머지 1에 'a'를 더해 'b'인 상태에서 -1을 하여 'a'가 되는 것이다.
다시 index 반복문으로 돌아와서 두 번째 이동은 스킵 이동이다. letter가 의무 이동으로 바뀔 때마다 현재 letter가 skip에 있는 글자중 하나가 아닌지 검사한다. for문을 이용해 skip에 있는 모든 글자들을 돌며 letter과 같은 글자가 있는지 찾아낸다. 만약 같은 글자가 있다면 letter을 한 칸 이동(스킵이동) 시키고 똑같이 'z'를 넘어갔다면 조정한다.
마지막으로 그렇게 스킵 이동을 한 후 letter의 상태가 또 스킵이동이 가능한 상태일 수 있기 때문에 k를 -1로 초기화 한다. skip 반복을 다시 돌겠다는 이야기이다. 만약 letter의 상태가 스킵이동이 불가능한 상태라면 반복문을 빠져나와 다음 의무 이동을 할 것이다.
의무이동과 스킵 이동이 끝나면 다음 글자로 넘어가기전 이동을 마친 letter를 answer에 저장한다. 그리고 이 과정을 s를 다 훑어볼 때까지 반복한다.
오답 노트
index만큼 이동할 때 하나씩 보지 않고
#include <string>
#include <vector>
#include <iostream>
using namespace std;
string solution(string s, string skip, int index) {
string answer = "";
int origin_index=index;
for(int i=0; i<s.length(); i++)
{
index=origin_index;
// 그냥 index만 했을 때는 s[i]~s[i]+index인데
for(int j=0; j<skip.length(); j++)
{
// 그 사이에 skip 문자들이 끼어있다면 하나씩 더 더함
if(skip[j]<=s[i]+index&&skip[j]>s[i])
{
index++;
//cout<<s[i]<<" : "<<skip[j]<<"포함 넘어감"<<endl;
}
}
char ch=s[i]+index;
if(ch>'z')
{
ch='a'+ch%'z'-1;
}
answer+=ch;
}
return answer;
}
#include <string>
#include <vector>
using namespace std;
char adjust_to_lowerAZ(char ch)
{
//cout<<(int)('a'+ch%'z'-1)<<endl;
if(ch<='z')
{
return ch;
}
else
{
return (char)('a'+ch%'z'-1);
}
}
string solution(string s, string skip, int index) {
string answer = "";
for(int i=0; i<s.length(); i++)
{
char letter=s[i];
for(int j=0; j<index; j++)
{
for(int k=0; k<skip.size(); k++)
{
if(letter==skip[k])
{
letter++;
letter=adjust_to_lowerAZ(letter);
break;
}
}
letter++;
letter=adjust_to_lowerAZ(letter);
for(int k=0; k<skip.size(); k++)
{
if(letter==skip[k])
{
letter++;
letter=adjust_to_lowerAZ(letter);
break;
}
}
}
answer+=letter;
}
return answer;
}
#include <string>
#include <vector>
using namespace std;
// z를 넘어갔는지 확인하고 조정하는 함수
char adjust_to_lowerAZ(char ch)
{
if(ch<='z') // z를 넘어가지 않았다면
{
return ch; // 그대로 반환
}
else // z를 넘어갔다면
{
return (char)('a'+ch%'z'-1); // 조정하여 반환
}
}
string solution(string s, string skip, int index) {
string answer = "";
for(int i=0; i<s.length(); i++)
{
char letter=s[i]; // letter 초기화
// index까지 하나씩 이동
for(int j=0; j<index; j++)
{
// 의무 이동
letter++; // 한 칸 이동
letter=adjust_to_lowerAZ(letter); // z를 넘어갔으면 조정
// 스킵 이동
for(int k=0; k<skip.size(); k++)
{
// letter가 skip에 있는 문자 중 하나라면
if(letter==skip[k])
{
letter++; // 한 칸 이동
letter=adjust_to_lowerAZ(letter); // z를 넘어갔으면 조정
k=0; // k 초기화(이동한 글자로 다시 skip 확인)
}
}
}
answer+=letter; // 최종 글자 추가
}
return answer;
}
문제 링크
https://school.programmers.co.kr/learn/courses/30/lessons/155652#
프로그래머스
SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
'Code KATA > 알고리즘 코드카타' 카테고리의 다른 글
[2025.02.10] 개인정보 수집 유효기간 (0) | 2025.02.10 |
---|---|
[2025.02.07] 햄버거 만들기 (1) | 2025.02.07 |
[2025.02.05] 대충 만든 자판 (0) | 2025.02.05 |
[2025.02.24] 문자열 나누기 (0) | 2025.02.04 |
[2025.02.03] 체육복 (1) | 2025.02.03 |