[백준 17298] 오큰수(Java)

최민길(Gale)·2023년 1월 5일
1

알고리즘

목록 보기
2/172

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

이 문제는 주어진 N의 값이 1,000,000이므로 완전탐색으로 풀 경우 반복문을 2번 이상 돌게 되어 시간 초과가 나게 됩니다. 따라서 이 문제는 반복을 최소로 하면서 어떻게 효과적으로 문제를 해결할 수 있을지에 대한 고민이 필요합니다.

이 문제는 문제 자체를 잘 해석해보면 쉽게 접근할 수 있습니다. 오큰수를 구하는 방법은 자기 자신보다 오른쪽에 있으면서 큰 수 중 가장 왼쪽에 있는 수입니다. 즉 여기서 쪼개서 생각해볼 수 있는 부분은 크게 3가지입니다.

  1. 자기 자신보다 크다
  2. 자기 자신보다 오른쪽에 있다
  3. 여러 후보군들 중 가장 왼쪽에 있다(가장 먼저 나온 값이다)

위의 3가지 조건을 코드로 구현하면 됩니다. 반복문을 돌려 자기 자신에서부터 오른쪽으로 이동시키고(2번 조건 만족), 자기 자신보다 크다면(1번 조건 만족), 결과 배열에 넣은 후 더 이상 오른쪽으로 이동시키지 않는 방법으로 구현하면 됩니다.(3번 조건 만족)

하지만 이 부분을 코드로 직접 구현하기에는 복잡한 부분이 많았습니다. 우선 문제에 나와 있는 [9,5,4,8]의 경우처럼 제일 앞의 수가 가장 클 경우 배열을 다시 한 번 돌아야하기 때문에 결국 시간 초과가 발생합니다.

따라서 이 부분을 해결하기 위해 스택을 사용한 임시 저장 공간을 도입했습니다. 자기 자신의 인덱스를 스택에 저장하고, 반복문을 통해 오른쪽으로 계속 이동시키다가 스택의 peek 값보다 큰 값이 나타나게 된다면 스택 안에 저장되어있는 모든 인덱스를 현재의 수로 치환, 그렇지 않다면 다시 스택에 인덱스를 저장하여 궁극적으로 스택에는 현재 바라보고 있는 수보다 작은 수들만 존재하게 되어 오큰수를 확인할 수 있습니다.

스택을 사용한 이유는 자기 자신의 수가 아닌 오른쪽으로 이동 중에 발견되는 수를 기준으로 가장 왼쪽에 있는 수가 가장 최근에 검사한 수이기 때문입니다. 즉 LIFO 구조로 되어 있기 때문에 스택으로 문제를 해결하였습니다.

다음은 문제 풀이 코드입니다.

import java.util.*;
import java.io.*;

public class Main{
    static int N;
    static int[] req = new int[1000001];
    static int[] res = new int[1000001];
    static Stack<Integer> stack = new Stack<>();

    public static void main(String[] args) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());

        st = new StringTokenizer(br.readLine());
        for(int i=0;i<N;i++){
            req[i] = Integer.parseInt(st.nextToken());
            res[i] = -1;
        }

        for(int i=0;i<N;i++){
            // 스택에 있는 가장 최근의 숫자와 현재 숫자와 비교해서 현재 숫자가 더 클 경우 스택에 있는 모든 인덱스를 현재 숫자로 넣기
            while(!stack.isEmpty() && req[stack.peek()] < req[i]){
                int idx = stack.pop();
                res[idx] = req[i];
            }
            // 현재 숫자의 인덱스를 저장
            stack.push(i);
        }

        // 출력 수가 많기 때문에 반복문을 돌려 System.out 진행 시 너무 느림
        // StringBuilder를 통해 한번에 출력
        StringBuilder sb = new StringBuilder();
        for(int i=0;i<N;i++){
            sb.append(res[i]);
            sb.append(" ");
        }
        System.out.println(sb);
    }
}

profile
저는 상황에 맞는 최적의 솔루션을 깊고 정확한 개념의 이해를 통한 다양한 방식으로 해결해오면서 지난 3년 동안 신규 서비스를 20만 회원 서비스로 성장시킨 Software Developer 최민길입니다.

0개의 댓글

관련 채용 정보