ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [프로그래머스/JAVA] 괄호 회전하기
    Algorithm/Java 2024. 12. 1. 16:32

    https://school.programmers.co.kr/learn/courses/30/lessons/76502

     

    프로그래머스

    SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

    programmers.co.kr

    📌 문제 요약 

     

    주어진 문자열을 왼쪽으로 x칸씩 회전하며 올바른 괄호 문자열이 되는 경우를 찾아야 하는 문제입니다. 올바른 괄호 문자열의 정의는 다음과 같습니다:

    1. (), [], {}는 올바른 괄호 문자열입니다.
    2. A가 올바른 괄호 문자열이라면, (A), [A], {A}도 올바른 괄호 문자열입니다.
    3. A, B가 올바른 괄호 문자열이라면, AB도 올바른 괄호 문자열입니다.

    [ 오답 노트 ]

    ❌ 기존 오답 코드

    import java.util.*;
    
    class Solution {
        public int solution(String s) {
            int answer = 0;
            
            for(int i = 0; i < s.length(); i++) {
                StringBuilder sb = new StringBuilder();
                sb.append(s); // sb = "[](){}"
                // [](){}      ->   ](){}[   
                // 인덱스 0의 값 -> 인덱스 5의 값
                // 인덱스 1의 값 -> 인덱스 0의 값
                // 인덱스 2의 값 -> 인덱스 1의 값
                // ...
                // 인덱스 5의 값 -> 인덱스 4의 값
                for(int j = 0; j < sb.length(); j++) {
                    sb.setCharAt(j, sb.charAt(sb.length()-1-j));
                } // sb = "](){}["
                
                // 올바른 괄호 문자열인지 판별
                Stack<Character> st = new Stack<>();
                for(int z = 0; z < sb.length(); z++) {
                    if(sb.charAt(z) == '{' || sb.charAt(z) == '(' || sb.charAt(z) == '[') {
                        st.push(sb.charAt(z));
                    }else{ // sb.charAt(i) == '}' || sb.charAt(i) == ')' || sb.charAt(i) == ']'
                        if(st.isEmpty()) {
                            continue;
                        }
                        st.pop();
                    }
                }
                
                if(st.isEmpty()) {
                    answer += 1;
                }
                
            }
            
            return answer;
        }
    }



    📌 기존 코드의 문제점

     

    1. 문자열 회전 방식 오류

     

    문제에서는 "문자열을 왼쪽으로 x칸 회전"해야 하지만, 기존 코드인  sb.setCharAt(j, sb.charAt(sb.length()-1-j));은 문자열을 반대로 뒤집는 방식(역순 문자열 생성)으로 처리하고 있다. 

    아래와 같은 방식으로 s.substring(i)로 인덱스 i부터 끝까지의 문자열과 s.substring(0,i)를 사용해 맨 처음 인덱스부터 i-1까지의 문자열을 합치면 왼쪽으로 i칸 회전한 결과가 된다.

    // 문자열 회전
    String rotated = s.substring(i) + s.substring(0, i);

     

     

    2. 올바른 괄호 판별 로직 오류

     

    stack을 사용하는 방식은 맞지만 닫는 괄호(],),}) 가 올바른 짝인지 확인하지 않았다. 기존 코드는 스택이 비어있지만 않으면 올바른 짝이라고 생각하고 pop해서 없애게 되어있어 올바른 로직이 아니다. 

     

    아래와 같이 st.peek()의 값이 여는 괄호([,(,{) 가 되면 pop하도록 하는 조건을 추가해야 한다. 

    각 괄호마다 짝이 맞아야 되므로 (c == '}' && 조건도 각각 추가해야 된다. 

     

    또한 flag 변수를 추가해서 괄호 문자열 검증 과정에서 올바르지 않은 상태를 발견하면 추가 검사를 하지 않도록 한다. 

     boolean flag = true; // 처음에는 유효하다고 가정
     ...
     } else {
                        if (st.isEmpty() || 
                            (c == '}' && st.peek() != '{') || 
                            (c == ')' && st.peek() != '(') || 
                            (c == ']' && st.peek() != '[')) {
                            flag = false; // 유효하지 않음으로 상태 변경
                            break;
                        }
                        st.pop();
            }
            // 유효한 경우에만 처리
                 if(flag && st.isEmpty()) {
                    answer++;
                }
            }

     

     

    3. 효율성 문제

     

    StringBuilder를 매번 생성하고 회전처리를 수행하기 때문에 문자열 길이가 길이가 길어질수록 성능이 저하된다. 

     




    [ 정답 코드 & 올바른 풀이 ]


    📌 정답 코드

    import java.util.*;
    
    class Solution {
        public int solution(String s) {
            int answer = 0;
            // 1. 문자열 회전
            for(int i = 0; i < s.length(); i++) {
                String rotated = s.substring(i) + s.substring(0,i);
                // 2. 올바른 괄호 판별
                Stack<Character> st = new Stack<>();
                boolean flag = true;
    
                for(int j = 0; j < rotated.length(); j++) {
                    char c = rotated.charAt(j);
                    if(c == '[' || c == '{' || c == '(') {
                        st.add(c);
                    }else { // 다 닫는 괄호
                        if(st.isEmpty() ||
                            (c == '}' && st.peek() != '{') || 
                            (c == ')' && st.peek() != '(') || 
                            (c == ']' && st.peek() != '[')) {
                            flag = false;
                            break;
                        }
                        st.pop();
                    }
                }
    
                if(flag && st.isEmpty()) {
                    answer++;
                }
            }
    
            return answer;
        }
    }
    반응형
Designed by Tistory.