프로그래머스 -특정 문자 제거하기 (+StringBuilder)

김민아·2025년 4월 4일

코딩테스트

목록 보기
5/7
post-thumbnail

💡문제 설명
문자열 my_string과 문자 letter이 매개변수로 주어집니다. my_string에서 letter를 제거한 문자열을 return하도록 solution 함수를 완성해주세요.


예를들어

  • 주어진 my_string 문자열 : abcdef
    letter : f
    return 값 : abcde
  • 주어진 my_string 문자열 : BCBdbe
    letter : B
    return 값 : Cdbe




🧾기존 작성한 코드 -에러

처음엔 letter이랑 비교한 후 같은 문자면 StringBuffer의 deleteCharAt() 함수로 삭제하면 되겠다 해서 다음과 같은 코드를 작성했다.

class Solution {
    public String solution(String my_string, String letter) {
        String answer = "";
        
        StringBuffer sb = new StringBuffer(my_string);
        
        for(int i=0; i<=my_string.length()-1; i++){
            if(my_string.charAt(i) == letter.charAt(0)){
                sb.deleteCharAt(i);
            }
        }
        answer = sb.toString();
        
        return answer;
    }
} 

첫번째 예제는 통과 했지만 두번째 예제에서 결과가 `Cdbe` 가 아닌 `CBbe` 가 나와서 실패했다. 왜 B가 삭제되는게 아니라 엉뚱한 d가 삭제됐나 했더니 문자 삭제는 sb 객체에서 이루어지지만 for문과 if문에서는 아무생각 없이 my_string으로 letter와 비교를 하고있었기 때문이였다.

즉, 이미 sb객체에서는 제일 처음 B가 삭제되었지만 my_string에서는 B가 삭제되지 않은 상태이기 때문에 인덱스가 달라진다. 예제2에서 오류가 난것도 첫번째 B가 삭제되면서 인덱스가 달라졌고 두번째 B자리에 있던 d가 삭제된 것이다.



🧾기존 작성한 코드2 -에러

sb를 삭제하면 당연히 기존의 my_string 문자열과 달라지므로 sb객체의 문자열과 letter를 비교하도록 수정 해준다.

class Solution {
    public String solution(String my_string, String letter) {
        String answer = "";
        
        StringBuffer sb = new StringBuffer(my_string);
        
        for(int i=0; i<=sb.length()-1; i++){
            if(sb.charAt(i) == letter.charAt(0)){
                sb.deleteCharAt(i);
            }
        }
        answer = sb.toString();
        
        return answer;
    }
} 

실행 결과 예제 두개는 통과 하였지만 제출하니 테스트 20개 중 두개가 실패하였다. sb 객체안에 문자가 삭제 될때마다 인덱스가 앞으로 밀려서 조건문에 걸리지 않는 문자가 생기기 때문이다. 통과했던 예제 같은 경우에는 운좋게 조건문에 걸리지 않는 문자가 삭제해야하는 문자가 아니라서 에러가 나지 않은것이다.

Cd자리에 삭제해야할 문자열 B가 있었으면 이 예제도 에러난다.



🧾제출한 코드 -통과


class Solution {
    public String solution(String my_string, String letter) {
        String answer = "";
        
        StringBuffer sb = new StringBuffer(my_string);
        
        for(int i=0; i<sb.length(); i++){
            if(sb.charAt(i) == letter.charAt(0)){
                sb.deleteCharAt(i);
                i--;   //문자를 삭제한다면 인덱스는 1을 줄여줌
            }
        }
        answer = sb.toString();
        
        return answer;
    }
} 

문자를 삭제한 후에 뒤에있던 문자들이 앞으로 한칸씩 밀려서 문제가 발생하므로 조건문에서 문자가 삭제된다면 i를 -1시켜서 밀려진 문자를 건너뛰지 않게 조정한다.



🔨개선한 코드A

//기존 코드 
StringBuffer sb = new StringBuffer(my_string); 
 

//개선한 코드
StringBuilder sb = new StringBuilder(my_string);

StringBuffer는 멀티스레드 환경에서 효율이 좋지만, 단일스레드이니까 더 가벼운 StringBuilder가 적절하다. 실제로 성능을 비교해보니 StringBuffer를 사용했을때보다 실행시간이 더 단축되었다.


StringBuffer와 StringBuilder 성능 비교

🔻반복문을 사용한 코드로 StringBuffer와 StringBilder의 성능 비교해보기


+) StringBuilder?

StringBuilder는 어제 작성했던 StringBuffer와 마찬가지로 Java에서 가변 문자열을 다루기 위한 클래스이다. 즉, 문자열을 만들고 나서도 내용을 자유롭게 수정할 수 있다.


💡StringBuilder의 주요 메서드(StringBuffer와 같다)

메서드설명
append(String s)문자열 추가
insert(int offset, String s)특정 위치에 문자열 삽입
replace(int start, int end, String s)특정 범위 문자열 대체
delete(int start, int end)특정 범위 문자열 삭제
reverse()문자열 뒤집기
toString()StringBuffer → String 변환


StringBuffer와 StringBuilder는 동기화 때문에 성능에 차이가 발생한다. StringBuffer는 모든 메서드가 동기화 되어있기 때문에 여러 쓰레드가 동시에 접근했을때 순서를 보장해준다. 하지만 순서를 보장하기위해 락(lock)기능이 있기 때문에 성능은 느려진다. 반면에 StringBuilder는 동기화가 없고 락 없이 바로 실행되기 때문에 실행 속도가 더 빠르다. StringBuilder 자체가 락이 필요 없는 단일쓰레드를 성능 낭비 없이 더 빠르게 실행시키기 위해 Java5 부터 만들어졌다.
때문에 단일 쓰레드에서는 StringBuilder를, 멀티쓰레드에서는 StringBuffer를 사용하는게 좋다.



🔨개선한 코드B

//기존 코드 
for(int i=0; i<sb.length(); i++){
            if(sb.charAt(i) == letter.charAt(0)){
                sb.deleteCharAt(i);
                i--;   
            }
}
answer = sb.toString(); 



//개선한 코드
answer = my_string.replace(letter, "");

반복문을 돌 필요 없이 자바의 replace() 함수에 ""을 넣으면 그냥 간단하게 삭제할 수 있다...
코드도 훨씬 간결해졌고 StringBuilder로 직접 삭제한 것과 동일한 효과를 준다.


profile
천천이 꾸준히

0개의 댓글