-
[백준/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]] } } } }
📌 기존 코드의 문제점
- 스택 활용 부족
- 기존 코드에서는 탑의 높이를 비교할 때, stack.pop()과 stack.peek()를 통해 하나씩 비교해가는 구조였습니다. 이렇게 접근하면 모든 탑을 계속해서 검사해야 하므로 불필요한 연산이 발생합니다.
- 효율적으로 스택을 활용하여 높이가 낮은 탑은 제거하면서 비교하는 방식이 아니어서, 시간 복잡도에서 불리하게 작용합니다.
- 코드의 반복과 비효율성
- 기존 코드에서는 stack.pop()과 stack.peek()를 반복하며 왼쪽 방향의 모든 탑을 비교하고 있지만, 현재 탑보다 낮은 탑들은 제거해도 상관없습니다. 높이가 높은 탑만 남겨두면 레이저 신호가 도달하지 않는 탑을 배제할 수 있습니다.
- 출력 방식의 문제
- 코드의 결과를 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