문제

수직선 위에 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 ≤ N ≤ 1,000,000
  • -109 ≤ Xi ≤ 109

예제 입력 1 

5

2 4 -10 4 -9

예제 출력 1

2 3 0 3 1

 

import java.util.*;
import java.io.*;
import java.math.*;
import java.security.Key;

public class Q18870 {

		public static void main(String[] args) throws IOException {
	        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	        int cnt = Integer.parseInt(br.readLine());
	        StringTokenizer st = new StringTokenizer(br.readLine()," ");
	        int res[] = new int [cnt];
	        
	        HashMap<Integer,Integer> xymap = new HashMap<Integer,Integer>();
	        
	        //map의 key 값은 중복 저장이 안되니, 사용자가 입력한 값을 key로받아서
	        for(int i=0;i<cnt;i++)
	        {
	            res[i]=Integer.parseInt(st.nextToken());
	            xymap.put(res[i],i);
	        }
		    br.close();   
	        int size = xymap.size();
       
	        //map의 key set을 value list에 넣고
	        ArrayList<Integer> value = new ArrayList<>();	        
	        Iterator<Integer> iter = xymap.keySet().iterator();
	        
	        while(iter.hasNext())
	        {
	             value.add(iter.next());
	        }
	        //오름차순 정렬
	        Collections.sort(value);
	        /*27~34까지가 단순히 오름차순 정렬을 위한 코드인데 좀 불필요한거같기도하고..
            넘긴거같기도하다 근데 map의 keyset만 바로 arraylist로 변환해서 저장하는 법을 모르겠음*/
	        
	        //key에 따른 좌표 압축된 숫자를 맞추어 map에 넣어주기
	        for(int i=0;i<size;i++)
	        {           
	            xymap.put(value.get(i),i);
	        }
	        
	        StringBuilder sb = new StringBuilder();
	        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
	        
	        //사용자가 입력했던 res배열값이 xmap에 key로 있다면, 해당 key의 value(좌표압축된 숫자) 뽑아서 sb에 저장
	        for(int i=0;i<cnt;i++)
	        {
	                if(xymap.containsKey(res[i]))
	                  {
	                    sb.append(xymap.get(res[i])+" ");        	
	                  }
	         }      
	        
	        bw.write(sb.toString());
	        bw.flush();
	        bw.close();
	    }
	}

<제출 결과>

 

시간초과의 늪에서 허우적거리다가, 어드바이스를 받고 불필요한 이중 for문을 단일 for문(코드 맨마지막 for문)으로 바꾸고 bw 및 sb를 사용하여 시간을 줄였다.

 

나는 애초에 사용자가 입력한 키값의 중복을 제거하기위해 바로 map으로 입력받고,

중복이 제거된 map의 keyset을 arraylist로 변환하기위해 iterator를 사용하게되었다.

그런데 이 단계에서 시간이 너무 오래걸렸다.......

 

그렇게해서 정리하자면 아래와 같은 순서로 코드가 작성되었는데

[입력값 map에 put (중복값 제거) -> keyset 분리 (iterator 사용) -> arraylist 변환 (오름차순) -> 매칭하여 다시 map에 put(좌표 압축)]

다 제출하고 나서 비교해보니, 차라리 arraylist로 입력받고 오름차순 바로 sort로한 다음에, map 넣는게 굉장히 깔끔한것 같았다.

 

요렇게

[입력값 arraylist (오름차순) -> map에 put (중복값 제거) -> 매칭하여 다시 map에 put(좌표 압축)]

 

아무튼 더 좋은 방법은 항상 많은 것 같다. 힘내야지

+ Recent posts