[백준 1725] 히스토그램(Java)

최민길(Gale)·2024년 1월 31일
1

알고리즘

목록 보기
170/172

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

이 문제는 세그먼트 트리를 이용하여 풀 수 있습니다. 최대 면적의 히스토그램 면적은 범위 내의 가장 작은 높이 x 범위 구간의 길이가 됩니다. 이 때 세그먼트 트리의 특성상 특정 구간 내의 최소값을 빠르게 구할 수 있기 때문에 풀이에 적합합니다.

우선 트리에 인덱스 정보를 추가하는 방식으로 세그먼트 트리를 초기화합니다. 이 후 구간 내의 최솟값 인덱스를 구한 후 구간의 길이와 그 인덱스가 가리키는 원소의 값의 곱을 계산합니다.

여기서 현재 구간보다 왼쪽 혹은 오른쪽으로 더 확장 가능한지를 체크하기 위해 현재 인덱스 값을 좌우로 1씩 증가시키는 구간의 면적을 계산하여 최댓값을 갱신합니다.

다음은 코드입니다.

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

class Main{
    static int N;
    static int[] tree;
    static int[] arr;

    public static void main(String[] args) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        N = Integer.parseInt(br.readLine());
        arr = new int[N];
        for(int i=0;i<N;i++) arr[i] = Integer.parseInt(br.readLine());

        int size = getTreeSize(N);
        tree = new int[size];
        init(1,0,N-1);
        System.out.println(getArea(0,N-1));
    }

    private static long getArea(int left, int right){
        int min = getMin(1,0,N-1,left,right);
        long area = (long)(right-left+1) * (long)arr[min];

        if(min+1 <= right){
            long newArea = getArea(min+1,right);
            area = Math.max(area, newArea);
        }
        if(min-1 >= left){
            long newArea = getArea(left,min-1);
            area = Math.max(area,newArea);
        }
        return area;
    }

    private static int getMin(int node, int start, int end, int left, int right){
        if(end<left || right<start) return -1;
        if(end<=right && left<=start) return tree[node];

        int mid = (start+end)/2;
        int leftIdx = getMin(node*2,start,mid,left,right);
        int rightIdx = getMin(node*2+1,mid+1,end,left,right);

        if(leftIdx == -1) return rightIdx;
        else if(rightIdx == -1) return leftIdx;
        else return arr[leftIdx] <= arr[rightIdx] ? leftIdx : rightIdx;
    }

    private static int getTreeSize(int N){
        int H = 0;
        int L = N;
        while(L>0){
            H++;
            L /= 2;
        }
        return (int) Math.pow(2,H+1);
    }

    private static void init(int node, int start, int end){
        if(start == end) tree[node] = start;
        else{
            int mid = (start+end)/2;
            init(node*2,start,mid);
            init(node*2+1,mid+1,end);

            if(arr[tree[node*2]] <= arr[tree[node*2+1]]) tree[node] = tree[node*2];
            else tree[node] = tree[node*2 +1];
        }
    }
}

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

0개의 댓글

관련 채용 정보