Post

[이것이 코딩 테스트다 with Python] 괄호 변환(Java)

Goal

“이것이 코딩 테스트다 with Python” 교재의 문제를 분석하고 코드와 함께 이해해보기 위한 글입니다.

문제 분석

구현 문제? 인 것 같네요.

코드 구현

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
public class ParenthesesConversion {
    public static void main(String[] args) throws IOException { //p346
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String a = br.readLine(); //입력
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        bw.write(solution(a));
        br.close();
        bw.close();
    }

    public static String solution(String p) {
        // 1. 올바른 괄호 문자열이라면, 바로 문자열을 반환한다.
        if (check(p)) return p;
        // 2. 올바른 괄호 문자열로 변환, 반환한다.
        return split(p);
    }

    // 올바른 괄호 문자열 판단 메소드.
    public static boolean check(String str) {
        // 1. '(' 의 개수를 세는 변수.
        int open = 0;
        // 2. 첫 문자가 ')'인 경우는 올바른 괄호 문자열인 경우가 아니므로 false.
        if (str.charAt(0) == ')') return false;
        // 3. 문자열 탐색.
        for (int i = 0; i < str.length(); i++) {
            // 4. '('의 개수를 카운팅.
            if (str.charAt(i) == '(') open++;
            else {
                // 5. ')'를 만나면 open 감소.
                open--;
                // 6. 카운팅 과정에서 open이 음수가 되면 '('의 개수보다 ')'의 개수가 많아지는 순간이므로 올바른 괄호 문자열이 아니다. 따라서 false.
                if (open < 0) return false;
            }
        }
        // 7. 위 조건을 모두 통과하면 "올바른 괄호 문자열"이다.
        return true;
    }

    // 균형잡힌 괄호 문자열 -> 올바른 괄호 문자열 변환 메소드.
    public static String split(String w) {

        // 입력된 문자열 w를 u와 v로 나누어 저장하는 StringBuilder 클래스 객체.
        StringBuilder u = new StringBuilder();
        StringBuilder v = new StringBuilder();

        // 1. 빈 문자열인 경우, 빈 문자열을 반환.
        if (w.length() == 0) return "";

        // 2. 문자열 w를 두 "균형잡힌 괄호 문자열" u,v로 분리.
        // 2-1. '('의 개수를 저장하는 변수.
        int open = 0;
        for (int i = 0; i < w.length(); i++) {
            // 한 문자가 '('인 경우 open은 증가.
            if (w.charAt(i) == '(') open++;
                // ')'인 경우 open은 감소.
            else open--;

            // 2-2. 처음 open이 0이 된 경우가 가장 작은 단위의 "균형잡힌 괄호 문자열".
            if (open == 0) {
                // 2-3. 해당 인덱스를 기점으로 u와 v로 분리.
                u.append(w.substring(0, i + 1));
                v.append(w.substring(i + 1, w.length()));

                // 3. u가 "올바른 괄호 문자열"이라면,
                if (check(u.toString())) {
                    // 3-1. v에 대해 재귀호출 후, u에 이어 붙인다. 이 과정 후 break에 걸려 u를 반환하므로 변환 과정에 성립.
                    u.append(split(v.toString()));
                    // 4. u가 "올바른 괄호 문자열"이 아니라면,
                } else {
                    // 새로운 문자열을 만들어야 한다.
                    StringBuilder s = new StringBuilder();
                    // 4-1. (를 붙인다.
                    s.append("(");
                    // 4-2. v에 대해 재귀호출 후 붙인다.
                    s.append(split(v.toString()));
                    // 4-3. )를 붙인다.
                    s.append(")");
                    // 4-4. u를 조작해 붙인다.
                    s.append(reverse(u.toString()));
                    // 16. 새로운 문자열을 반환한다.
                    return s.toString();
                }
                break;
            }
        }
        // 17. u가 올바른 문자인 경우에만 반환되는 u.
        return u.toString();
    }

    // 문자열을 뒤집는 메소드.
    public static String reverse(String str) {
        // 새로운 문자열을 선언.
        StringBuilder s = new StringBuilder();

        // 1. 변환 과정 -> 첫 번째, 마지막 문자를 제외하고 반복.
        for (int i = 1; i < str.length() - 1; i++) {
            // 1-1. '(' -> ')'
            if (str.charAt(i) == '(') s.append(")");
                // 1-2. ')' -> '('
            else s.append("(");
        }
        // 2. 변환된 문자열을 반환.
        return s.toString();
    }

}
This post is licensed under CC BY 4.0 by the author.