• Feed
  • Explore
  • Ranking
/
/
    맞았습니다!!

    BOJ : 백준 2230 수고르기(JAVA)

    백준 2230 수 고르기 자바 풀이 💡
    알고리즘투포인터
    t
    t1s
    2025.04.24
    ·
    4 min read

    문제

    문제
    N의 정수로 이루어진 수열 A[1], A[2], ... A[N]이 있다. 이 수열에서 두 수(같은 수일 수도 있음)를 골랐을 때 그 차이가 M 이상이면서 제일 작은 경우를 출력하라.
    시간 제한 : 2초
    메모리 제한 : 128MB

    입력
    N M
    arr[0]
    arr[1]
    ...
    arr[N]

    풀이

    순차적인 자료 구조(array)를 사용할 때 포인터를 옮겨가며 답을 찾을 수 있을 것 같아 투 포인터 알고리즘을 사용하기로 했다. start = 0, end = length-1로 잡아야 할지, start = 0, end = 0으로 잡아야 할지를 고민했다.

    start = 0, end = length-1 이면
    M보다 클 때 end를 줄일 것이다. (end를 줄여야 M보다 작은 수가 나올 테니까)
    생각해보면 아래와 같은 반례를 금방 떠올릴 수 있었다.
    N = 5, M = 2
    arr = 1 2 7 7 8 13

    처음엔 end = 5고 start = 0이니까 10-1 = 9
    여기서 점점 end를 줄여가다보면...
    답은 13-7 혹은 7-1한 6이다
    13-1 = 12
    8-1 = 7
    7-1 = 6
    2-1 = 1 > M => start를 늘린다?
    이러면 start == end니까 end++ start++...?
    비효율적이다...
    그리고 건너뛰는 숫자가 없어야 하는데, 위와 같은 방법으로는 건너뛰게 되는 값들이 생긴다.


    그래서 start = 0, end = 0일 때로 구현해보았다.

    생각한 플로우는 다음과 같다.

    arr[end] - arr[start] < M ⇒ end++
    arr[end] - arr[start] > M ⇒ start++
    if start end ⇒ end++
    if start - end
    M ⇒ return(더 찾을 필요 X)

    위의 플로우에 따라 작성한 코드는 이렇다.

    import java.util.*;
    import java.io.*;
    
    public class Main {
    
    	public static void main(String[] args) throws Exception {
    		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    		StringTokenizer st = new StringTokenizer(br.readLine());
    	
    		int N = Integer.parseInt(st.nextToken());
    		int M = Integer.parseInt(st.nextToken());
    		int[] arr = new int[N];
    		for(int i = 0; i<N; i++) {
    			arr[i] = Integer.parseInt(br.readLine());
    		}
    		
    		Arrays.sort(arr);
    		int res = Integer.MAX_VALUE;
    		int start = 0;
    		int end = 1;
    		while(end<N) {
    			int diff = arr[end] - arr[start];
    			
    			if(diff == M) {
    				System.out.println(M);
    				return;
    			} else if(diff > M) {
    				start++;
    				res = Math.min(res, diff);
    			} else {
    				end++;
    			}
    			
    			if(end == start) {	
    				end++;
    			}
    		}
    		System.out.println(res);
    	}
    
    }

    문제를 풀며

    특정 값을 찾는 문제라면 end = length-1로 시작하는 게 낫다는 걸 깨닫게 됐다.
    왜냐면 조건에 따라 end를 줄이고 start를 늘리다보면 건너뛰게 되는 쌍이 있을 것이기 때문에... (1,n) (2,n) (3,n) ... (n-1, n) 이렇게 모든 쌍들을 일일히 확인하고 넘어가게 되는 게 아니라, (1, n) (2, n) (3, n-1) (3, n-2) 이런 식으로 조건에 만족하는 범위 내로만 탐색하므로 건너뛰게 되는 쌍들이 존재한다.

    알고리즘은 애플리케이션에서 어떻게 돌아갈지와 스스로 반례를 찾아낼 때 제일 재미있는 것 같다🤓 뇌에 쥐 나는 감각 ㅎㅎ







    - 컬렉션 아티클