본문 바로가기
Algorithm

백준 1935번 :: 후위 표기식2

by DaSsom 2023. 4. 5.

https://www.acmicpc.net/problem/1935

 

1935번: 후위 표기식2

첫째 줄에 피연산자의 개수(1 ≤ N ≤ 26) 가 주어진다. 그리고 둘째 줄에는 후위 표기식이 주어진다. (여기서 피연산자는 A~Z의 영대문자이며, A부터 순서대로 N개의 영대문자만이 사용되며, 길이

www.acmicpc.net

 

1. 스택을 사용하여 해결

2. 피연산자에 대응하는 값이 영어 대문자일 경우, push

3. 연산자를 만났을 때, pop을 두 번 하여 그 숫자들의 연산 수행

4. 연산결과 다시 push 

5. 반복

 

고민했던 부분

1) double rs = arr[c - 'A'];

   => 배열 arr 에서 어떻게 값을 가져와야할까?

   => 가만보니.. 아스키 코드값을 빼주면 어떨까?

   => 'A' - 'A'  = 0 / 'B' - 'A'  = 1 / 'C' - 'A' = 2 ...

        문제에서 ABCDE... 순서대로 주고있으니 모든 대문자에서 A를 빼주면 되겠구나!

 

2) answer = pop2 / pop1;

   => 처음엔 별생각없이 pop1 / pop2 로 썼음

   => 예제로 예를 들면, 4/5가 되어야하는데 5/4가 되고 있었음

   => 다른 연산자는 문제없었으나 '/' 연산에서 문제 발생

   => 스택은 First In Last Out 의 구조이기 때문에 '/' 연산은 순서가 중요했다

 

public class n1935 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(br.readLine()); // 피연산자 개수 = 5
        String cmd = br.readLine();              // 후위표기식 : ABC*+DE/-

        // 피연산자 갯수 크기의 int 배열 만들고 배열에 피연산자 대응하는 값 넣기
        int[] arr = new int[N]; // 1 2 3 4 5
        for (int i = 0; i < N; i++) {
            arr[i] = Integer.parseInt(br.readLine());
        }

        // 스택 배열 생성 -> cmd의 입력값이 영어 대문자이면 arr의 0번 원소부터 push
        // 연산자를 만나면 숫자 두개 pop 해당 연산 수행 -> 연산 결과 다시 push
        // 마지막 출력이 소숫점 둘째 자리까지 이므로 스택은 double
        Stack<Double> stk = new Stack<>();
        for (int i = 0; i < cmd.length(); i++) {
            char c = cmd.charAt(i); // A, B, C, *, +, D, E, /, -
            // A ~ Z 대문자이면
            if (c >= 'A' && c <= 'Z') {
                double rs = arr[c - 'A']; // arr[0] arr[1] arr[2] arr[3] arr[4]
                stk.push(rs);             // arr 원소 스택에 push
            }
            // 연산자를 만났다면?
            else {
                // 스택에서 pop 두 번 , 연산결과 push
                double pop1 = 0.0;
                double pop2 = 0.0;
                double answer = 0.0;
                switch (c) {
                    case '*':
                        pop1 = stk.pop();
                        pop2 = stk.pop();
                        answer = pop2 * pop1;
                        stk.push(answer);
                        break;
                    case '+':
                        pop1 = stk.pop();
                        pop2 = stk.pop();
                        answer = pop2 + pop1;
                        stk.push(answer);
                        break;
                    case '/':
                        pop1 = stk.pop();
                        pop2 = stk.pop();
                        answer = pop2 / pop1;
                        stk.push(answer);
                        break;
                    case '-':
                        pop1 = stk.pop();
                        pop2 = stk.pop();
                        answer = pop2 - pop1;
                        stk.push(answer);
                        break;
                }

            }
        }
        System.out.println(String.format("%.2f", stk.pop()));
    }
}

 

3) 리팩토링

   => 정리하면서 본건데.. pop과 push 가 쓸데없이 중복된 부분이 많은 듯 하다.

         줄일 수 있을 거 같아~!

 else {
                // 스택에서 pop 두 번 , 연산결과 push
                double pop1 = stk.pop();
                double pop2 = stk.pop();
                double answer = 0.0;
                switch (c) {
                    case '*':
                        answer = pop2 * pop1;
                        break;
                    case '+':
                        answer = pop2 + pop1;
                        break;
                    case '/':
                        answer = pop2 / pop1;
                        break;
                    case '-':
                        answer = pop2 - pop1;
                        break;
                }
                stk.push(answer);

 

훨씬 .. 깔끔? 😊