두 문자열 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 함수를 완성해주세요.
import java.util.*;
class Solution {
public String solution(String s, String skip, int index) {
//변경
StringBuilder answer = new StringBuilder();
Set<Character> skipSet = new HashSet<>();
for(char ch : skip.toCharArray()){
skipSet.add(ch);
}
for(int i = 0; i<s.length(); i++){
char c = s.charAt(i);
for(int j = 0; j<index; j++){
c = (char)(c + 1);
//변경
if(c > 'z'){
c = 'a';
}
while(skipSet.contains(c)){
c = (char)(c+1);
if(c > 'z'){
c = 'a';
}
}
}
answer.append(c);
}
return answer.toString();
}
}
skip 배열을 좀 더 편리하게 찾고, 문자열을 효율적으로 관리하기 위해 StringBuilder와 set을 선언
skip의 문자들을 skipSet으로 이동
전체 s를 돌면서 c라는 char 변수에 문자 하나씩 넣어줌
c를 index만큼 1씩 더해주는데, 이때 c가 z보다 커지면 a로 바꿔준다.
그리고 c가 skipSet에 있는 문자라면 다시 앞의 내용을 반복한다.
마지막으로 구한 c를 answer에 붙여준다.
import java.util.*;
class Solution {
public String solution(String s, String skip, int index) {
String answer = "";
for(int i = 0; i<s.length(); i++){
char c = s.charAt(i);
for(int j = 0; j<index; j++){
c = (char)(c + 1);
for(int p = 0; p<skip.length(); p++){
if(skip.charAt(p) == c){
c = (char)(c+1);
}
if(c >= '{'){
c = 'a';
}
}
}
answer += c;
}
return answer;
}
}
스트링빌더와 set을 사용하지 않고 시도한 초기 코드이다.
이 코드의 문제점은 c가 아스키코드 상에서 z를 넘어가는 경우를 제대로 처리하지 못하고 있다는 점과, 무한루프에 빠질 수 있다는 점이다.
그리고 추가적으로 stringBuilder와 set을 사용하지 않았기에 조금은 복잡하다.
stringBuilder와 set을 평소에 거의 사용하지 않아서 아직 어색하여 정리해 보고자 한다.
문자열을 효율적으로 다룰 수 있는 클래스
자바의 String은 불변의 특성을 가짐 -> 문자열을 변경할 때마다 새로운 객체 생성! => 성능 저하
반면, StringBuilder는 가변 객체
[사용 예시]
public class Main {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("Hello");
// 문자열 추가
sb.append(" World");
System.out.println(sb); // Hello World
// 문자열 삽입
sb.insert(6, "Java ");
System.out.println(sb); // Hello Java World
// 문자열 삭제
sb.delete(5, 10);
System.out.println(sb); // Hello World
// 문자열 변경
sb.replace(6, 11, "Programmer");
System.out.println(sb); // Hello Programmer
// 문자열 뒤집기
sb.reverse();
System.out.println(sb); // remmargorP olleH
}
}
다양한 문자열 조작 메서드를 제공하기 때문에 문자열 관련 문제를 풀 때 꼭 써보기...!
Set은 이미 정리한 적이 있어서, 개념보다는 언제 사용해야 좋은지를 알아보았다.
주로 List와 Set을 혼동하거나 잘못 사용하는 경우가 많은데, 둘은 개념이 다르기 때문에 이를 비교하며 정리했다.
| 특징 | List | Set |
|---|---|---|
| 순서 | 삽입 순서 유지 | 순서 보장 안 됨 (LinkedHashSet이나 TreeSet은 예외) |
| 중복 허용 | 중복 허용 | 중복 허용 안 됨 |
| 접근 시간 | 인덱스를 통해 O(1) | 인덱스 접근 불가 |
| 검색 시간 | O(n) | HashSet의 경우 O(1) |
| 사용 예시 | 순서가 중요하거나 중복 허용 (예: 로그, 큐) | 고유값 보장 및 빠른 검색이 필요할 때 (예: 유일한 ID, 중복되지 않는 요소) |