문제 링크: https://www.acmicpc.net/problem/22866

 

22866번: 탑 보기

3번째 건물에서 볼 수 있는 건물은 2, 4, 8번째 건물로 총 3개를 볼 수 있다. 그 중 3번째 건물과 가장 가까운 건물은 2, 4번째 있는 건물로 이 중 번호가 작은 번호인 2가 답이 된다.

www.acmicpc.net

▶문제

일직선으로 다양한 높이의 건물이 총 N개가 존재한다. 각 건물 옥상에서 양 옆에 존재하는 건물의 옆을 몇 개 볼 수 있는지 궁금해졌다.

 i번째 건물 기준으로 i−1, i−2,..., 1번째 건물은 왼쪽에, i, i, ..., N번째 건물은 오른쪽에 있다. 각 건물 사이의 거리는 다 동일하다.

현재 있는 건물의 높이가 L이라고 가정하면 높이가 L보다 큰 곳의 건물만 볼 수 있다.

바라보는 방향으로 높이가 L인 건물 뒤에 높이가 L 이하인 건물이 있다면 가려져서 보이지 않는다.

번호 1 2 3 4 5 6 7 8
높이 3 7 1 6 3 5 1 7
보이는 건물 번호 2 x 2, 4, 8 2, 8 2,4,6,8 2,4,8 2,4,6,8 x

각 건물에서 볼 수 있는 건물들이 어떤 것이 있는지 구해보자.

▶입력

첫 번째 줄에 건물의 개수 N이 주어진다.

두 번째 줄에는 N개의 건물 높이가 공백으로 구분되어 주어진다.

▶출력

 i(1≤i≤N) 번째 건물에서 볼 수 있는 건물의 개수를 출력한다.

만약 볼 수 있는 건물의 개수가 1개 이상이라면 i번째 건물에서 거리가 가장 가까운 건물의 번호 중 작은 번호로 출력한다.

▶해설

Stack을 활용해서 푸는 문제입니다. 단 Stack을 두 번 사용해야 합니다. 

 

데이터 세팅

 

건물의 데이터 나타내는 클래스

class Building{
int index;
int height;
public Building(int index, int height) {
this.index = index;
this.height = height;
}
}

 

arr -> 건물들의 정보

indexAndGap -> 건물들의 Index와 Index 차이 값을 담는 배열(가장 큰 차이는 10만이므로 차이 값은 100001로 초기화)

cnt -> 보이는 건물의 수

Building[] arr = new Building[n+1];
int [][] indexAndGap = new int[n+1][2];
int [] cnt = new int[n+1];
for(int i=1; i<=n; i++){
arr[i] = new Building(i, Integer.parseInt(s[i-1]));
Arrays.fill(indexAndGap[i],100001);
}

 

 

1. 왼쪽에 보이는 건물의 개수를 센다.

Stack에 들어있는 건물 중에서 자신보다 작거나 같으면 보이지 않는 건물입니다. 따라서 자신보다 크거나, 비어있을 때까지 pop을 진행하고 남은 Stack의 size가 보이는 건물의 수입니다

while(!stack.isEmpty() && stack.peek().height<=arr[i].height){
stack.pop();
}
cnt[i] += stack.size();

 

그 후 Stack이 비어있지 않다면 보이는 건물이 존재하는 것입니다. Index의 차이가 가장 적은 건물의 Index를 구하면 됩니다. 

if(!stack.isEmpty()){
int gap = Math.abs(stack.peek().index-i);
if(gap<indexAndGap[i][1]){ // Index 차이가 더 적다면 무조건 바꾼다.
indexAndGap[i][0] = stack.peek().index;
indexAndGap[i][1] = gap;
}
// Index 차이는 같지만, 건물의 번호가 다를 경우 건물 번호만 바꾼다.
else if(gap == indexAndGap[i][1] && stack.peek().index<indexAndGap[i][0]){
indexAndGap[i][0] = stack.peek().index;
}
}

 

2. 오른쪽에 보이는 건물의 수를 센다

이렇게 왼쪽에 보이는 건물을 진행했으므로 동일하게 방법으로 순서를 반대로 해서 오른쪽에 보이는 건물을 진행하면 됩니다. 

for(int i=n; i>=1; i--){
while(!stack.isEmpty() && stack.peek().height<=arr[i].height){
stack.pop();
}
cnt[i] +=stack.size();
if(!stack.isEmpty()){
int gap = Math.abs(stack.peek().index-i);
if(gap<indexAndGap[i][1]){
indexAndGap[i][0] = stack.peek().index;
indexAndGap[i][1] = gap;
}
else if(gap == indexAndGap[i][1] && stack.peek().index<indexAndGap[i][0]){
indexAndGap[i][0] = stack.peek().index;
}
}
stack.push(arr[i]);
}

 

전체 코드

import java.io.*;
import java.lang.reflect.Array;
import java.util.*;
import java.lang.*;
class Building{
int index;
int height;
public Building(int index, int height) {
this.index = index;
this.height = height;
}
}
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());
Stack<Building> stack = new Stack<>();
String[] s = br.readLine().split(" ");
Building[] arr = new Building[n+1];
int [][] indexAndGap = new int[n+1][2];
int [] cnt = new int[n+1];
for(int i=1; i<=n; i++){
arr[i] = new Building(i, Integer.parseInt(s[i-1]));
Arrays.fill(indexAndGap[i],100001);
}
for(int i=1; i<=n; i++){
while(!stack.isEmpty() && stack.peek().height<=arr[i].height){
stack.pop();
}
cnt[i] += stack.size();
if(!stack.isEmpty()){
int gap = Math.abs(stack.peek().index-i);
if(gap<indexAndGap[i][1]){
indexAndGap[i][0] = stack.peek().index;
indexAndGap[i][1] = gap;
}
else if(gap == indexAndGap[i][1] && stack.peek().index<indexAndGap[i][0]){
indexAndGap[i][0] = stack.peek().index;
}
}
stack.push(arr[i]);
}
stack =new Stack<>();
for(int i=n; i>=1; i--){
while(!stack.isEmpty() && stack.peek().height<=arr[i].height){
stack.pop();
}
cnt[i] +=stack.size();
if(!stack.isEmpty()){
int gap = Math.abs(stack.peek().index-i);
if(gap<indexAndGap[i][1]){
indexAndGap[i][0] = stack.peek().index;
indexAndGap[i][1] = gap;
}
else if(gap == indexAndGap[i][1] && stack.peek().index<indexAndGap[i][0]){
indexAndGap[i][0] = stack.peek().index;
}
}
stack.push(arr[i]);
}
StringBuilder sb = new StringBuilder();
for(int i=1; i<=n; i++){
if(cnt[i]==0){
sb.append(0).append("\n");
}
else{
sb.append(cnt[i]).append(" ").append(indexAndGap[i][0]).append("\n");
}
}
System.out.println(sb.toString());
}
}