https://school.programmers.co.kr/learn/courses/30/lessons/12926
문자열 s의 각 알파벳을 n만큼 밀어서 암호문을 만드는 문제. 공백은 그대로 두고, z를 밀면 a로 순환한다는 조건이 포인트다.
s는 알파벳 대/소문자, 공백으로만 구성n은 1~25일단 골격만 잡고 시작했다.
for(int i=0; i<s.length(); i++){
int nowIdx=0;
boolean capital = false;
if(s.charAt(i)==" "){
continue;
}
if(s.charAt(i)>=65 && s.charAt(i)<=90){
nowIdx= s.charAt(i)-'A';
capital =true;
}else if(s.charAt(i)>=97 && s.charAt(i)<=122){
nowIdx= s.charAt(i)-'a';
}
}
대/소문자 판별하고 기준점(nowIdx)까지는 구했는데, 정작 민 다음 실제로 밀어서 결과 문자열을 만드는 부분이 통째로 빠져 있었다. 여기서부터 하나씩 막힌 부분을 뚫어나갔다.
if(s.charAt(i)==" "){ // 에러
charAt()은 char를 반환하는데 " "는 String이라 비교가 안 됐다. char 리터럴은 작은따옴표(' ')로 써야 한다는 걸 놓치고 있었다.
z를 밀면 a가 된다는 조건을 보고, 처음엔 이걸 if문으로 따로 처리하려고 했다.
if(s.charAt(i)==90 && n>0){
nowIdx=65;
}
근데 이렇게 하면 nowIdx(0~25 범위여야 하는 값)에 65가 들어가버려서 이후 계산이 다 꼬였다. 게다가 이 조건을 소문자 분기 안에도 그대로 복붙해놔서, 애초에 진입 자체가 불가능한 죽은 코드였다.
돌아보니 순환은 애초에 % 26 연산 하나로 다 해결되는 문제였다. nowIdx가 25(z)이고 n=1이면 (25+1)%26 = 0, 즉 자동으로 a의 인덱스로 돌아간다. 특수 처리가 필요 없었고, 오히려 버그의 원인이었다.
nextIdx = (nowIdx + n) % 26;
핵심 정리: 몇 바퀴를 돌든 상관없이, % 26이 "26칸짜리 순환에서 최종적으로 위치한 자리"를 그대로 계산해준다. 순환 조건을 보면 반사적으로 나머지 연산부터 떠올려야 한다.
인덱스를 다시 문자로 바꾸는 부분에서 막혔다.
char chr = 'A' + nextIdx; // 컴파일 에러
Java에서 char와 int를 연산하면 결과가 자동으로 int로 승급(promotion)된다. 그래서 'A' + nextIdx는 int이고, 이걸 char 변수에 그대로 넣으려면 "possible lossy conversion" 에러가 난다. 명시적 캐스팅이 필요했다.
char chr = (char)('A' + nextIdx);
Character.toString()을 쓰려고 했는데, 이것도 캐스팅된 char를 넘겨야 의도한 오버로드(Character.toString(char))로 들어간다. 사실 StringBuilder는 append(char)를 바로 지원해서, 굳이 String으로 변환할 필요조차 없었다.
sb.append(chr);
디버깅하다 만든 int[] apb 배열과 System.out.println이 로직 어디에도 안 쓰여서 그대로 제거했다.
import java.util.Arrays;
class Solution {
public String solution(String s, int n) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
int nowIdx = 0;
int nextIdx = 0;
char chr = '0';
boolean capital = false;
if (s.charAt(i) == ' ') {
sb.append(' ');
continue;
}
if (s.charAt(i) >= 65 && s.charAt(i) <= 90) {
nowIdx = s.charAt(i) - 'A';
capital = true;
} else if (s.charAt(i) >= 97 && s.charAt(i) <= 122) {
nowIdx = s.charAt(i) - 'a';
}
nextIdx = (nowIdx + n) % 26;
if (capital) {
chr = (char) ('A' + nextIdx);
} else {
chr = (char) ('a' + nextIdx);
}
sb.append(chr);
}
return sb.toString();
}
}
예제 3개 다 통과 확인 완료 ("AB",1→"BC", "z",1→"a", "a B z",4→"e F d").
charAt()의 반환 타입은 char. String(" ")과 비교하면 컴파일 자체가 안 된다.if로 예외 처리하기 전에 % 연산으로 풀 수 있는지부터 생각하기. 오히려 특수 처리가 버그를 만들었다.char끼리, 혹은 char와 int를 연산하면 결과는 int. 다시 char에 담으려면 명시적 캐스팅 (char)가 필요하다.Character.toString()으로 문자열 변환 안 거치고 char를 바로 append할 수 있다.println은 로직 검증 후 지우기.