본문으로 건너뛰기
홈
기술
기술 전체
프로그래밍68
컴퓨터 과학63
AI48
웹 개발36
인프라33
데이터31
소프트웨어 공학18
소개
← 목록으로컴퓨터 과학 › 알고리즘 › 코딩 테스트

[BaekJoon-17298] 오큰수

목차

오큰수

문제

크기가 N인 수열 A = A1, A2, …, AN이 있다. 수열의 각 원소 Ai에 대해서 오큰수 NGE(i)를 구하려고 한다. Ai의 오큰수는 오른쪽에 있으면서 Ai보다 큰 수 중에서 가장 왼쪽에 있는 수를 의미한다. 그러한 수가 없는 경우에 오큰수는 -1이다.

예를 들어, A = [3, 5, 2, 7]인 경우 NGE(1) = 5, NGE(2) = 7, NGE(3) = 7, NGE(4) = -1이다. A = [9, 5, 4, 8]인 경우에는 NGE(1) = -1, NGE(2) = 8, NGE(3) = 8, NGE(4) = -1이다.

입력

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000,000)이 주어진다. 둘째에 수열 A의 원소 A1, A2, …, AN (1 ≤ Ai ≤ 1,000,000)이 주어진다.

출력

총 N개의 수 NGE(1), NGE(2), …, NGE(N)을 공백으로 구분해 출력한다.

예제 입력 1

4
3 5 2 7

예제 출력 1

5 7 7 -1

예제 입력 2

4
9 5 4 8

예제 출력 2

-1 8 8 -1

풀이

각 위치에서 오른쪽을 끝까지 탐색하면 최대 백만 원소에 대해 O(N²)이 된다. 새 숫자를 왼쪽부터 읽을 때, 아직 오큰수를 못 찾은 인덱스만 스택에 둔다. 현재 수 A[i]가 스택 꼭대기의 수보다 크면, A[i]가 그 인덱스에서 처음 만난 더 큰 오른쪽 수다. 꼭대기를 꺼내 답을 채우고, 더 이상 꺼낼 수 없을 때 현재 인덱스를 넣는다.

[3,5,2,7]을 보면 3의 인덱스가 먼저 쌓인다. 5를 읽는 순간 3을 꺼내 답 5를 적는다. 2는 5보다 작아 쌓인다. 마지막 7은 2와 5를 차례로 해결하고, 자기 자신은 해결되지 않은 채 남아 -1이 된다. 스택에는 아래에서 위로 값이 내림차순 또는 같은 값으로 남는다. 같은 값은 ‘큰’ 수가 아니므로 비교는 <여야 한다.

각 인덱스는 한 번 들어가고 최대 한 번 나오므로 시간 O(N), 수열·답·스택 공간 O(N)이다. N이 백만이어서 split(" ")로 백만 개 문자열을 만들면 메모리 부담이 크다. 아래 코드는 바이트 입력과 정수 배열 스택을 사용한다. 모두 같은 수인 경우 답은 전부 -1이며, 엄격한 비교를 확인하는 경계 사례다.

소스코드

import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.util.Arrays;

public class Main {
    public static void main(String[] args) throws Exception {
        FastScanner in = new FastScanner();
        int n = in.nextInt();
        int[] numbers = new int[n];
        int[] answer = new int[n];
        int[] stack = new int[n]; // 아직 오큰수를 못 찾은 인덱스
        Arrays.fill(answer, -1);
        int size = 0;

        for (int i = 0; i < n; i++) {
            numbers[i] = in.nextInt();
            while (size > 0 && numbers[stack[size - 1]] < numbers[i]) {
                answer[stack[--size]] = numbers[i];
            }
            stack[size++] = i;
        }

        StringBuilder result = new StringBuilder(n * 3);
        for (int i = 0; i < n; i++) {
            if (i > 0) result.append(' ');
            result.append(answer[i]);
        }
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
        out.write(result.toString());
        out.newLine();
        out.flush();
    }

    static class FastScanner {
        private final BufferedInputStream in = new BufferedInputStream(System.in);
        private final byte[] buffer = new byte[1 << 16];
        private int length = 0, position = 0;

        int read() throws Exception {
            if (position >= length) {
                length = in.read(buffer);
                position = 0;
                if (length == -1) return -1;
            }
            return buffer[position++];
        }

        int nextInt() throws Exception {
            int ch;
            do { ch = read(); } while (ch <= ' ' && ch != -1);
            int value = 0;
            while (ch > ' ') {
                value = value * 10 + ch - '0';
                ch = read();
            }
            return value;
        }
    }
}

문제 사이트 : https://www.acmicpc.net/problem/17298

같은 카테고리의 글