본문 바로가기

Dot Algo∙ DS/PS

[BOJ] 백준 3015번 오아시스 재결합 (Java)

    #3015 오아시스 재결합

    난이도 : 골드 1

    유형 : 자료구조 / 스택 

     

    3015번: 오아시스 재결합

    첫째 줄에 줄에서 기다리고 있는 사람의 수 N이 주어진다. (1 ≤ N ≤ 500,000) 둘째 줄부터 N개의 줄에는 각 사람의 키가 나노미터 단위로 주어진다. 모든 사람의 키는 231 나노미터 보다 작다. 사람

    www.acmicpc.net

    ▸ 문제

    오아시스의 재결합 공연에 N명이 한 줄로 서서 기다리고 있다.

    이 역사적인 순간을 맞이하기 위해 줄에서서 기다리고 있던 백준이는 갑자기 자기가 볼 수 있는 사람의 수가 궁금해 졌다.

    두 사람 A와 B가 서로 볼 수 있으려면, 두 사람 사이에 A 또는 B보다 키가 큰 사람이 없어야 한다.

    줄에 서있는 사람의 키가 주어졌을 때, 서로 볼 수 있는 쌍의 수를 구하는 프로그램을 작성하시오.

     입력

    첫째 줄에 줄에서 기다리고 있는 사람의 수 N이 주어진다. (1 ≤ N ≤ 500,000)

    둘째 줄부터 N개의 줄에는 각 사람의 키가 나노미터 단위로 주어진다. 모든 사람의 키는 231 나노미터 보다 작다.

    사람들이 서 있는 순서대로 입력이 주어진다.

     출력

    서로 볼 수 있는 쌍의 수를 출력한다.

     

    문제 풀이  

    스택을 활용하여 각 조건에 따라 쌍을 매칭해주면 된다. 분기만 잘해주면 된다.

     

    0. 먼저 stack이 비어있지 안으면 기존에 stack에 저장되어 있는 값 중에 자신보다 낮은 키를 가진 사람들과 매칭해준다.

    • 매칭해준다음 낮은 키의 데이터는 삭제한다. 왜냐하면 현재 새로 저장되는 키 때문에 그 건너에 있는 사람을 볼 수 없기 때문이다

     

    1. stack이 비어있는 경우

    • 새로운 사람의 키 데이터를 추가한다.

    2. stack이 비어있지 않은 경우

    • 2-1) 새로운 사람의 키가 가장 가까이에 있는 사람보다 키보다 작을 경우
      • 서로 쌍을 맺어주고 값을 더해준다. 왜냐하면 기존의 사람보다 키가 작기 때문에 기존에 있는 사람은 다음 사람과도 쌍을 이룰 수 있기 때문이다.
    • 2-2) 새로운 사람이 가장 가까이에 있는 사람보다 키가 같은 경우
      • 키가 같은 사람끼리 연결해주고 stack에 저장된 해당 키의 카운트를 늘려준다.
      • 그리고 기존의 가장 큰 사람과도 연결을 맺어준다. 

     

     

      과정 1 stack 과정2 stack result
    push2 1번과정 진행
    push(2)
    2 - - 0
    push4 0번 과정 진행
    (2,4) 매칭 후 2 삭제
    0 1번 과정 진행
    push(4)
    4 1
    push1 2-1)번 과정 진행 
    (4,1) 매칭 
    1, 4 - - 2
    push2 0번 과정 진행
    (1, 2) 매칭 후 1 삭제
    2, 4 2-1)번 과정 진행
    (2,4) 매칭
    2, 4 4
    push2 2-2)번 과정 진행
    (2,2) 매칭 후 2의 카운트 증가
    2(2), 4 2-2)번 과정 진행
    (2, 4) 매칭
    2(2), 4 6
    push5 0번 과정 진행
    (2(2), 5) 매칭
    (4, 5) 매칭
    0 1번 과정 진행
    push(5)
    5 9
    push1 2-1)번 과정 진행
    (5,1) 매칭
    5,1 - - 10

     

    풀이 코드 

    import java.io.*;
    import java.util.Stack;
    
    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());
    		
    		int[] arr = new int[n];
    		for(int i=0; i<n; i++) {
    			arr[i] = Integer.parseInt(br.readLine());
    		}
    		
    		long result = 0;
    		Stack<int[]> s = new Stack<>();
    		for(int i=0; i<n; i++) {
    			while(!s.isEmpty() && s.peek()[0] < arr[i]) {
    				result+= s.pop()[1];
    			}
    			
    			if(s.isEmpty()) {
    				s.push(new int[] {arr[i],1});
    			}else {
    				if(s.peek()[0] > arr[i]) {
    					s.push(new int[] {arr[i],1});
    					result++;
    				} else {
    					result+= s.peek()[1]++;
    					if(s.size()>1) result++; 
    				}
    			}
    		}
    		System.out.println(result);
    	}
    }