알고리즘/백준

[JAVA] 백준 18870번 좌표 압축

Dogvelop 2020. 10. 21. 15:19

문제

수직선 위에 N개의 좌표 X1, X2, ..., XN이 있다. 이 좌표에 좌표 압축을 적용하려고 한다.

Xi를 좌표 압축한 결과 X'i의 값은 Xi > Xj를 만족하는 서로 다른 좌표의 개수와 같아야 한다.

X1, X2, ..., XN에 좌표 압축을 적용한 결과 X'1, X'2, ..., X'N를 출력해보자.

 

 

입력

첫째 줄에 N이 주어진다.

둘째 줄에는 공백 한 칸으로 구분된 X1, X2, ..., XN이 주어진다.

 

 

출력

첫째 줄에 X'1, X'2, ..., X'N을 공백 한 칸으로 구분해서 출력한다.

 

 

 

풀이과정

1. value값과 index값을 가진 GET 노드를 정의한다.

( 처음 풀이과정에서 sort 두 번 하기위해서 만들었는데 그냥 그대로 이용 )

 

public static class GET{
		int val;
		int idx;
		public GET(int val, int idx) {
			this.val = val;
			this.idx = idx;
		}
	}

 

2. ArrayList arr ( 입력으로 받은 value값을 순서대로 가지는 리스트 ) ,

val_idx ( 입력받은 value, 값과 입력받은 순서대로 index를 부여한 GET 노드를 가지는 리스트 ) 생성 및 입력받기

 

public static ArrayList<Integer> arr = new ArrayList<>();;
public static ArrayList<GET> val_idx = new ArrayList<>();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		StringBuilder sb = new StringBuilder();
		
		N = Integer.parseInt(br.readLine());
		
		StringTokenizer st = new StringTokenizer(br.readLine());
		for(int i=0; i<N; i++) {
			int num = Integer.parseInt(st.nextToken());
			arr.add(num);
			val_idx.add(new GET(num, i));
		}

 

3. value값을 기준으로 오름차순 정렬

 

Collections.sort(val_idx, new Comparator<GET>() {
            @Override
            public int compare(GET s1, GET s2) {
                if (s1.val < s2.val) {
                    return -1;
                } else if (s1.val > s2.val) {
                    return 1;
                }
                return 0;
            }
        });

 

4. val_idx 리스트를 처음부터 반복문을 이용해서 중복된 값 제거하기

 

for(int i=0; i<val_idx.size(); i++) {
			if(i == 0) {
				keep = val_idx.get(i).val;
			}
			else {
				if(keep == val_idx.get(i).val) {
					val_idx.remove(i);
					i--;
				}
				else {
					keep = val_idx.get(i).val;
				}
			}
		}

 

5. BinarySearch 구현

 

public static int BinarySearch(int pos) {
		int left = 0;
		int right = val_idx.size() - 1;

		while(left < right){
			int mid = (left + right ) / 2;
			if(val_idx.get(mid).val >= pos)
				right = mid;
			else
				left = mid + 1;
		}
		return right;
	}

 

6. BinarySearch를 이용해서 답 구하기

 

for(int i=0; i<arr.size(); i++){
			int result = BinarySearch(arr.get(i));
			sb.append(result + " ");
		}
		
System.out.println(sb);

 

+. 배열에 result값들을 입력받아 반복문을 통해서 답을 출력하니 시간초과

++. 그래서 StringBuilder 사용해서 했는데도 시간초과 -> 이유를 모르겠음

 

 

Solution ( 시간초과 )

import java.util.*;

import java.io.*;

public class BaekJoon_18870_좌표압축 {
	
	public static class GET{
		int val;
		int idx;
		public GET(int val, int idx) {
			this.val = val;
			this.idx = idx;
		}
	}
	
	public static int N, keep;
	public static ArrayList<Integer> arr = new ArrayList<>();;
	public static ArrayList<GET> val_idx = new ArrayList<>();
	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		StringBuilder sb = new StringBuilder();
		
		N = Integer.parseInt(br.readLine());
		
		StringTokenizer st = new StringTokenizer(br.readLine());
		for(int i=0; i<N; i++) {
			int num = Integer.parseInt(st.nextToken());
			arr.add(num);
			val_idx.add(new GET(num, i));
		}
		
		Collections.sort(val_idx, new Comparator<GET>() {
            @Override
            public int compare(GET s1, GET s2) {
                if (s1.val < s2.val) {
                    return -1;
                } else if (s1.val > s2.val) {
                    return 1;
                }
                return 0;
            }
        });
		
		for(int i=0; i<val_idx.size(); i++) {
			if(i == 0) {
				keep = val_idx.get(i).val;
			}
			else {
				if(keep == val_idx.get(i).val) {
					val_idx.remove(i);
					i--;
				}
				else {
					keep = val_idx.get(i).val;
				}
			}
		}
		
		for(int i=0; i<arr.size(); i++){
			int result = BinarySearch(arr.get(i));
			sb.append(result + " ");
		}
		
		System.out.println(sb);
		br.close();

	}
	
	public static int BinarySearch(int pos) {
		int left = 0;
		int right = val_idx.size() - 1;

		while(left < right){
			int mid = (left + right ) / 2;
			if(val_idx.get(mid).val >= pos)
				right = mid;
			else
				left = mid + 1;
		}
		return right;
	}

}