ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [백준/JAVA] 2493번: 탑
    Algorithm/Java 2024. 10. 19. 15:42

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

     

    📌 문제 설명 요약

    • KOI 통신연구소에서는 왼쪽 방향으로 레이저 신호를 보내는 탑들의 구조를 실험 중입니다.
    • 각 탑에서 발사한 레이저 신호는 가장 먼저 만나는 왼쪽에 있는 탑에서만 수신됩니다.
    • N개의 탑이 있을 때, 각각의 탑에서 발사한 레이저 신호를 수신한 탑의 번호를 출력하는 프로그램을 작성합니다.

    - 오답 노트

     

    기존 오답 코드

    import java.io.*;
    import java.util.*;
    
    public class Main {
        public static void main(String[] args) throws IOException {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            int N = Integer.parseInt(br.readLine()); // 5
            Stack<int[]> stack = new Stack<>();
            StringTokenizer st = new StringTokenizer(br.readLine());
            // 6 9 5 7 4
    
            for(int i = 1; i <= N; i++) {
                int height = Integer.parseInt(st.nextToken());
                stack.push(new int[]{i, height}); // 탑들의 [번호, 높이] 순서로 저장
                // stack[[1,6], [2,9], [3,5], [4,7], [5,4]]
            }
    
            String answer = "";
            while(!stack.isEmpty()) {
                int[] a = stack.pop(); // [5,4]
                int[] b = stack.peek(); // [4,7]
                // [[1,6], [2,9], [3,5], [4,7]]
    
                if(a[1] <= b[1]) { // ex) 4 < 7
                    // 탑 번호 답에 추가
                    answer += b[0]; // 4
                } else{ // ex) 7 > 5   ---> 다음 비교로 넘어감 7 < 9
                    // a = [4,7]    ----> a = [4,7]
                    // b = [3,5]    ----> b = [2,9]
                    // [[1,6], [2,9], [3,5]]
    
                }
    
            }
    
    
        }
    }

     

    📌 기존 코드의 문제점

    1. 스택 활용 부족
      • 기존 코드에서는 탑의 높이를 비교할 때, stack.pop()과 stack.peek()를 통해 하나씩 비교해가는 구조였습니다. 이렇게 접근하면 모든 탑을 계속해서 검사해야 하므로 불필요한 연산이 발생합니다.
      • 효율적으로 스택을 활용하여 높이가 낮은 탑은 제거하면서 비교하는 방식이 아니어서, 시간 복잡도에서 불리하게 작용합니다.
    2. 코드의 반복과 비효율성
      • 기존 코드에서는 stack.pop()과 stack.peek()를 반복하며 왼쪽 방향의 모든 탑을 비교하고 있지만, 현재 탑보다 낮은 탑들은 제거해도 상관없습니다. 높이가 높은 탑만 남겨두면 레이저 신호가 도달하지 않는 탑을 배제할 수 있습니다.
    3. 출력 방식의 문제
      • 코드의 결과를 String answer로 누적하여 저장하려 했지만, 이는 반복문을 계속해서 수행하게 만들어 출력 성능을 떨어뜨립니다.
      • BufferedWriter와 같은 성능 최적화 출력을 사용하면 효율적으로 답을 출력할 수 있습니다.

     

     


     

     

    - 올바른 풀이

     

    📌 개선된 접근 방법

    • 스택 활용
      • 각 탑을 스택에 넣으면서 현재 탑보다 낮은 높이의 탑은 모두 제거합니다. 낮은 탑은 현재 탑에 의해 가려지기 때문에 제거해도 무방합니다.
      • 스택에는 [탑의 번호, 탑의 높이]를 저장하여, 특정 탑의 신호가 수신될 경우 가장 가까운 높이가 높은 탑을 쉽게 조회할 수 있게 합니다.
    • 최적화된 출력 방식
      • 결과값을 String answer로 누적하는 대신 BufferedWriter를 사용하여 출력 성능을 높였습니다.
    stack.peek()과 height 비교
    1. stack이 비어있을 때 stack[(1,6)] 추가
       answer 첫번째 값은 0
    2. stack [(1,6)]과 height 9 비교 ---> stack 6이 더 작으므로 stack에서 [1,6] 제거
       answer 두번째 값은 0
    3. stack [(2,9)]와 height 5 비교 ---> stack 9가 더 큼 ---> stack[[2,9], [3,5]]
       answer 세번째 값은 2
    4. stack [(3,5)]와 height 7 비교 ---> stack 3이 더 작으므로 stack에서 [3,5] 제거
       stack [(2,9)]와 height 7 비교 ---> stack 9가 더 큼 ---> stack[[2,9], [4,7]]
       answer 네번째 값은 2
    5. stack [(4,7)]와 height 4 비교 ---> stack 7이 더 큼
       answer 다섯번째 값은 4

     

    for(int i = 1; i <= N; i++) {
                // stack.peek()과 height 비교
                int height = Integer.parseInt(st.nextToken()); // 6
    
                while(!stack.isEmpty() && stack.peek()[1] < height) {
                    stack.pop();
                }
    
                if(!stack.isEmpty()) {
                    answer[i-1] = stack.peek()[0];
                }
    
                // stack[[1,6], [2,9], [3,5], [4,7], [5,4]]
                stack.push(new int[]{i, height}); // 탑들의 [번호, 높이] 순서로 저장
            }

    while을 사용하는 이유는 현재 탑이 왼쪽에 있는 여러 개의 낮은 탑들을 모두 건너뛰고, 가장 가까운 높은 탑을 찾아야 하기 때문입니다.

     

    if를 쓴다면, 현재 탑 바로 왼쪽에 있는 탑 하나만 검사할 수 있습니다. 하지만, 현재 탑보다 낮은 높이의 탑이 연속으로 여러 개 있다면, 이 탑들은 신호를 수신할 수 없기 때문에 모두 건너뛰어야 합니다. 그래서 while을 사용하여 연속된 낮은 탑들을 모두 제거하고, 가장 가까운 높은 탑만 남기는 겁니다.

     


     

    📌 정답 코드

    import java.io.*;
    import java.util.*;
    
    public class Main {
        public static void main(String[] args) throws IOException {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            int N = Integer.parseInt(br.readLine()); // 5
            Stack<int[]> stack = new Stack<>();
            StringTokenizer st = new StringTokenizer(br.readLine());
            // 6 9 5 7 4
            int[] answer = new int[N];
    
            for(int i = 1; i <= N; i++) {
                // stack.peek()과 height 비교
                // 1. stack이 비어있을 때 stack[(1,6)] 추가
                //    answer 첫번째 값은 0
                // 2. stack [(1,6)]과 height 9 비교 ---> stack 6이 더 작으므로 stack에서 [1,6] 제거
                //    answer 두번째 값은 0
                // 3. stack [(2,9)]와 height 5 비교 ---> stack 9가 더 큼 ---> stack[[2,9], [3,5]]
                //    answer 세번째 값은 2
                // 4. stack [(3,5)]와 height 7 비교 ---> stack 3이 더 작으므로 stack에서 [3,5] 제거
                //    stack [(2,9)]와 height 7 비교 ---> stack 9가 더 큼 ---> stack[[2,9], [4,7]]
                //    answer 네번째 값은 2
                // 5. stack [(4,7)]와 height 4 비교 ---> stack 7이 더 큼
                //    answer 다섯번째 값은 4
                int height = Integer.parseInt(st.nextToken()); // 6
    
                while(!stack.isEmpty() && stack.peek()[1] < height) {
                    stack.pop();
                }
    
                if(!stack.isEmpty()) {
                    answer[i-1] = stack.peek()[0];
                }
    
                // stack[[1,6], [2,9], [3,5], [4,7], [5,4]]
                stack.push(new int[]{i, height}); // 탑들의 [번호, 높이] 순서로 저장
            }
    
            // 결과 출력
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
            for(int i = 0; i < N; i++) {
                bw.write(answer[i] + " ");
            }
            bw.flush();
            bw.close();
        }
    }
    반응형

    'Algorithm > Java' 카테고리의 다른 글

    [백준/JAVA] 4358번 : 생태학  (0) 2024.10.22
    [백준/JAVA] 1620번: 나는야 포켓몬 마스터 이다솜  (0) 2024.10.22
    [백준/JAVA] 괄호의 값  (0) 2024.10.19
    [백준/JAVA] 쇠막대기  (0) 2024.10.19
    [백준/JAVA] 스택 수열  (0) 2024.10.19
Designed by Tistory.