백준 18870 좌표 압축 자바

꾸준하게 달리기~·2023년 7월 28일
0
post-thumbnail

문제는 다음과 같다.
https://www.acmicpc.net/problem/18870

풀이는 다음과 같다.

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

public class Main {

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        //배열 주어지고, index 잡고, 해당 index의 숫자보다, 더 작은 수가 배열에 몇개 있는지.
        //이분탐색 로어바운드 찾기. 단순히 정렬하고 index를 출력하면 안된다.

        int N = Integer.parseInt(br.readLine());
        ArrayList<Integer> a = new ArrayList<>(); //이건 받아놓고 중복 제거해줄 어레이리스트
        int[] arr = new int[N];

        StringTokenizer st = new StringTokenizer(br.readLine());
        for(int i = 0 ; i < N ; i++) {
            a.add(Integer.parseInt(st.nextToken()));
            arr[i] = a.get(i);
        }

        List<Integer> a1 = a.stream().distinct().collect(Collectors.toList()); //중복제거
        Collections.sort(a1); //정렬






        for(int i = 0 ; i < N ; i++) { //처음 주어진 입력값 배열 (arr[i] 하나하나씩 이분탐색 lowerbound찾기)
            int s = 0;
            int e = a1.size()-1;

            while(s < e) {
                int m = (s+e)/2;

                if(a1.get(m) >= arr[i]) e = m;
                else s = m+1;
            }

            bw.write(String.valueOf(e) + " ");
        }

        bw.flush();
        bw.close();
    }

}

이분탐색을 모르신다면?https://namu.wiki/w/%EC%9D%B4%EC%A7%84%20%ED%83%90%EC%83%89

이분탐색 로직을 안다는 가정 하에 다른 부분을 설명하자면,
배열이
1000 999 1000 999 1000 999 일때,
1 0 1 0 1 0 을 출력해야 한다.

즉 같은 값은 제거해주고,
오직
999 1000 만 남고 해당 값의 lower bound를 찾으면 된다는 소리이다.

음.. 무슨말인지 모르겠는걸! 싶으면, 아래의 로직을 보면 이해할 수 있다.




배열 압축은 에서 수행했다. (중복 제거 스트림)

List<Integer> a1 = a.stream().distinct().collect(Collectors.toList()); //중복제거

그다음 정렬했다.

 Collections.sort(a1); //오름차순 정렬

그다음, 원래 입력값 arr 배열을 순회하며,
각각 arr[i] 값의 lowerbound를 a1배열 (정렬 + 중복제거) 에서 찾아주었다.

예를 들어
1000 999 1000 999 1000 999 = arr 이라면
999 1000 = a1 이 되고,

arr[i]값은 차례로
1000
999
1000
999
1000
999 가 된다.

그럼 a1에서 위의 차례대로 lowerbound를 찾게되니,

999 1000 (a1) 에서 1000의 lowerbound -> 1
999 1000 (a1) 에서 999의 lowerbound -> 0
999 1000 (a1) 에서 1000의 lowerbound -> 1
999 1000 (a1) 에서 999의 lowerbound -> 0
999 1000 (a1) 에서 1000의 lowerbound -> 1
999 1000 (a1) 에서 999의 lowerbound -> 0

을 차례대로 출력해주면 되는것이다.
해당 내용이 아래의 코드이다.

for(int i = 0 ; i < N ; i++) { //처음 주어진 입력값 배열 (arr[i] 하나하나씩 이분탐색 lowerbound찾기)
            int s = 0;
            int e = a1.size()-1;

            while(s < e) {
                int m = (s+e)/2;

                if(a1.get(m) >= arr[i]) e = m;
                else s = m+1;
            }

            bw.write(String.valueOf(e) + " ");
        }

간단한 이분탐색 문제이다.

이분탐색 구현을 외워놓자.

		int s = 0;
        int e = 끝의 길이;

        while(s < e) {
            int m = (s+e)/2;

            if(arr[m] >= lowerbound를 찾길 원하는 값) e = m;
            else s = m+1;
        }
        
        여기서, whlie문을 빠져나오면 e값이 lowerbound가 된다.
profile
반갑습니다~! 좋은하루 보내세요 :)

0개의 댓글