알고리즘/자바

[백준 알고리즘] 2357번 자바(Java) 최솟값과 최댓값

2024. 10. 15. 11:43
목차
  1. 문제
  2. 입력
  3. 출력
  4. 풀이
  5. 소스코드

문제

N(1 ≤ N ≤ 100,000)개의 정수들이 있을 때, a번째 정수부터 b번째 정수까지 중에서 제일 작은 정수, 또는 제일 큰 정수를 찾는 것은 어려운 일이 아니다. 하지만 이와 같은 a, b의 쌍이 M(1 ≤ M ≤ 100,000)개 주어졌을 때는 어려운 문제가 된다. 이 문제를 해결해 보자.

여기서 a번째라는 것은 입력되는 순서로 a번째라는 이야기이다. 예를 들어 a=1, b=3이라면 입력된 순서대로 1번, 2번, 3번 정수 중에서 최소, 최댓값을 찾아야 한다. 각각의 정수들은 1이상 1,000,000,000이하의 값을 갖는다.

 

입력

첫째 줄에 N, M이 주어진다. 다음 N개의 줄에는 N개의 정수가 주어진다. 다음 M개의 줄에는 a, b의 쌍이 주어진다.

출력

M개의 줄에 입력받은 순서대로 각 a, b에 대한 답을 최솟값, 최댓값 순서로 출력한다.

 

풀이

범위에서의 최솟값 최댓값, 즉 세그먼트 트리를 사용해야 하는 문제다

세그먼트 트리의 init, find 메서드를 구현해야한다. 이분 탐색 방식을 배열로 구현한 알고리즘이라고 생각하면 된다

  • init: 트리 높이를 통해서 배열 높이를 정하고 이후 이분 탐색 방식을 통해서 값 채워주기
  • find: 채워진 배열을 토대로 범위에 맞는 누적합(또는 Math.min, Math.max)찾기

Init: 주어진 수 -> 트리 형태 -> 배열 형태로 되는 과정을 그림으로 보면 다음과 같다

  • 각 주어진 수를 비교해서 최솟값을 각 배열에 저장하면 된다. 계속해서 return Math.min을 해주면 제일 작은 값을 결국 각 부모 노드에 저장하게 된다.(부모 노드 입장에서는 왼&오 자식 중에 작은 값을 가지게 된다)
  • 위와 같은 방식으로 최댓값도 Math.max를 통해서 구할 수 있다

 

예제 입력 예시

10 4
75
30
100
38
50
51
52
20
81
5
1 10
3 5
6 9
8 10

 

예제 출력 예시

5 100
38 100
20 81
5 81

 

소스코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

// 2357번 최솟값과 최댓값
public class Main {
    private static int[][] tree; // 0은 min, 1은 max
    private static int[] arr;
    private static int treeSize;
    private static int left, right;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        StringBuilder sb = new StringBuilder();
        int N = Integer.parseInt(st.nextToken()); // N개의 정수
        int M = Integer.parseInt(st.nextToken()); // M개 만큼의 최솟값 최댓값 구하기

        int h = (int) Math.ceil(Math.log(N) / Math.log(2)); //높이 구하기 = 올림(루트 N); ex. 10이면 (3.3) -> 올림해서 4
        treeSize = (int) Math.pow(2, h + 1); // 2의 h승에다가 이진탐색(2배) 해줘야해서 2^(h+1)이 됨
        tree = new int[treeSize][2];
        arr = new int[N];

        // 값 추가
        for (int i = 0; i < N; i++) {
            arr[i] = Integer.parseInt(br.readLine());
        }

        tree[1][0] = minInit(1, 0, N-1);
        tree[1][1] = maxInit(1, 0, N-1);
        
        // 범위 최솟값, 최댓값 찾기
        for (int i = 0; i < M; i++) {
            st = new StringTokenizer(br.readLine());
            left = Integer.parseInt(st.nextToken())-1; // - 1 해줘야 index에 맞는 값
            right = Integer.parseInt(st.nextToken())-1; // -1 해줘야 index에 맞는 값
            sb.append(findMin(1, 0, N-1)).append(" ");
            sb.append(findMax(1, 0, N-1)).append("\n");
        }
        System.out.println(sb);
    }

    private static int minInit(int node, int start, int end) {
        if (start == end) return tree[node][0] = arr[start];

        return tree[node][0] = Math.min(minInit(node*2, start, (start+end)/2), minInit(node*2+1, (start+end)/2+1, end));
    }

    private static int maxInit(int node, int start, int end) {
        if (start == end) return tree[node][1] = arr[start];

        return tree[node][1] = Math.max(maxInit(node*2, start, (start+end)/2), maxInit(node*2+1, (start+end)/2+1, end));
    }

    private static int findMin(int node, int start, int end){
        //범위 벗어난 경우
        if(start > right || end < left) return 1000000000;

        //둘다 범위인 경우
        if(start >= left && end <= right) return tree[node][0];

        //그 외의 경우
        return Math.min(findMin(node*2, start, (start+end)/2), findMin(node*2+1, (start+end)/2+1, end));
    }

    private static int findMax(int node, int start, int end){
        //범위 벗어난 경우
        if(start > right || end < left) return 0;

        //둘다 범위인 경우
        if(start >= left && end <= right) return tree[node][1];

        //그 외의 경우
        return Math.max(findMax(node*2, start, (start+end)/2), findMax(node*2+1, (start+end)/2+1,end));
    }
}

 

 

 

 

문제 출처

https://www.acmicpc.net/problem/2357

 

저작자표시 (새창열림)

'알고리즘 > 자바' 카테고리의 다른 글

[백준 알고리즘] 17070번 자바(Java) 파이프 옮기기 1  (0) 2024.09.06
[백준 알고리즘] 2931번 자바(Java) 가스관  (0) 2024.08.29
[백준 알고리즘] 12100번 자바(Java) 2048(Easy)  (0) 2024.08.22
[SWEA] 6109번 자바(Java) 추억의 2048게임  (0) 2024.08.22
[백준 알고리즘] 12015번 자바(Java) 가장 긴 증가하는 부분 수열2  (0) 2024.08.17
  1. 문제
  2. 입력
  3. 출력
  4. 풀이
  5. 소스코드
'알고리즘/자바' 카테고리의 다른 글
  • [백준 알고리즘] 17070번 자바(Java) 파이프 옮기기 1
  • [백준 알고리즘] 2931번 자바(Java) 가스관
  • [백준 알고리즘] 12100번 자바(Java) 2048(Easy)
  • [SWEA] 6109번 자바(Java) 추억의 2048게임
Ash_jisu
Ash_jisu
Ash_jisu
JisuStory
Ash_jisu
전체
오늘
어제
  • 분류 전체보기 (136)
    • 알고리즘 (68)
      • 자바 (68)
      • C++ (0)
    • 자바(Java) (18)
    • 스프링 (7)
      • 테스트 (3)
    • 데이터베이스 (3)
      • SQL (7)
      • JPA (1)
      • ElasticSearch (3)
    • CS (3)
    • 배포, 운영 (6)
      • Infra (3)
    • 디자인 패턴 (8)
    • 기타 (6)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 프로그래머스 #알고리즘
  • 자바
  • db
  • 배포
  • 백준 #BFS
  • bfs #알고리즘
  • BFS
  • 백준
  • Elasticsearch #Testcontainer #Test
  • 자바 #백준
  • 백준 #DP
  • 자바 #그리디
  • 코딩테스트
  • swea #구현
  • java
  • Elasticsearch #최적화
  • 알고리즘 #bfs
  • 알고리즘 #다익스트라
  • API테스트 #Postman
  • dp

최근 댓글

최근 글

hELLO · Designed By 정상우.
Ash_jisu
[백준 알고리즘] 2357번 자바(Java) 최솟값과 최댓값
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.