[Java] 12926 시저암호
1. 문제
시저암호
2. 정답코드
내가 푼 방법은 엄밀히 말하면 좋은 코드는 아니다.
Z에서 한 칸 밀면 다시 A가 되고, z에서 밀면 a되는 걸 구현하는 부분에서 생각이 오래 걸렸다.
나는 단순하게 생각해서 A부터 Z까지 알파벳을 repeat()메서드로 두 번 이어 붙여서 해결했다.
ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ
for문으로 s를 순회하면서
- 대문자면 upper에서 n만큼 인덱스 이동
- 소문자면 lower에서 n만큼 인덱스 이동
→ 이동한 문자열을 StringBuilder에 추가 - 이 때 공백이나 특수문자는 그대로 추가한다.
class Solution {
public String solution(String s, int n) {
String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".repeat(2);
String lower = "abcdefghijklmnopqrstuvwxyz".repeat(2);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c >= 'a' && c <= 'z') {
int idx = c - 'a'; // 소문자 기준 인덱스
sb.append(lower.charAt(idx + n)); // n만큼 이동
} else if (c >= 'A' && c <= 'Z') {
int idx = c - 'A'; // 대문자 기준 인덱스
sb.append(upper.charAt(idx + n)); // n만큼 이동
} else {
sb.append(c); // 공백이나 특수문자는 그대로
}
}
return sb.toString();
}
}
그리고 소문자 'a'는 아스키 97, 대문자 'A'는 아스키 65라서 if문 분기점에서 웬만하면 소문자 먼저 쓰는게 좋다
repeat() 쓰지않고 아스키로만 구현한 코드
class Solution {
public String solution(String s, int n) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c >= 'a' && c <= 'z') { // 소문자 먼저 처리
sb.append((char) ('a' + (c - 'a' + n) % 26));
} else if (c >= 'A' && c <= 'Z') { // 그 다음 대문자 처리
sb.append((char) ('A' + (c - 'A' + n) % 26));
} else {
sb.append(c); // 공백, 숫자, 특수문자는 그대로
}
}
return sb.toString();
}
}
- 'A' + (c - 'A' + n) % 26
'A'를 기준으로 0~25 범위 만든 뒤 n만큼 이동하고,
26으로 나눈 나머지로 Z 넘어가는 걸 처리 - 'a' + (c - 'a' + n) % 26
소문자로 동일하게 처리 - 공백, 숫자는 그대로 붙임
(char) ('a' + (c - 'a' + n) % 26)
1. (c - 'a')
- 'c'가 예를 들어 'b'라고 하면
- 'b' - 'a' = 98 - 97 → 1
- 즉, 문자를 0~25 범위 인덱스로 바꾼 것
- 'a'는 0, 'b'는 1, .... 'z'는 25
2. (c - 'a' + n) % 26
- n만큼 밀고, 26으로 나머지 연산해서 Z넘어가면 다시 A로 돌아가게 처리하는 것이다
- 예를 들면 'z'+ 2 하면 (25 +2) % 26 = 1 이다. 1은 'b'가 된다.
3. 'a' + (...)
- 지금 위에까지 계산 결과는 0~25 숫자인데
- 다시 실제 아스키코드 문자로 변환하려면 'a'를 더해야 함
- 여기서 'a' 더하는 이유는 0~25 범위로 계산한 값을 다시 아스키 문자로 되돌리기 위해서이다.