알고리즘||코딩테스트/백준

[백준 2467번] 용액 - JAVA

째로스 2023. 8. 22. 15:53

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

 

2467번: 용액

첫째 줄에는 전체 용액의 수 N이 입력된다. N은 2 이상 100,000 이하의 정수이다. 둘째 줄에는 용액의 특성값을 나타내는 N개의 정수가 빈칸을 사이에 두고 오름차순으로 입력되며, 이 수들은 모두 -

www.acmicpc.net

풀이

사용한 알고리즘 : 이진 탐색, 우선순위 큐

 

풀이전략

보통의 이진 탐색에서는 mid(=(start+end)/2)를 사용하여 중간 값 기준으로 start와 end 위치를 변경한다.

하지만 이 문제 풀이에서는 중간 값이 아닌

양 끝의 범위를 양 끝에서 점점 조이는 방법을 활용하되 이진 탐색 구현 코드를 일부 사용했다.

 

양 끝 값의 합을 구하고, 그 값이 기존의 합 중 가장 작은 값보다 작으면

이번 연산에서의 합을 가장 작은 값으로 변경한다.

또한 합산에 사용된 양 끝 값을 저장해둔다.

 

만약 양 끝 값의 합이 0보다 큰 경우엔,더 작은 값을 구하기 위해 끝점을 1 더 앞당긴다. ( end = end-1 )

 

반대로 양 끝 값의 합이 0보다 작은 경우엔더 큰 값을 구하기 위해 시작점을 1 뒤로 미룬다. ( start = start +1 )

 

위 과정을 start>=end 가 될 때까지 반복하고그 때 저장해뒀던 양 끝 값의 합산이 가장 작은 경우의 양 끝 값을 출력하면 정답이 도출된다.

 

 

제출코드

1. 이진 탐색을 사용한 코드

import java.io.*;
import java.util.StringTokenizer;

public class Main {

    static int list[];
    static int minDiff = 2000000001;
    static int firstVal=0;
    static int secondVal=0;
    static void binarySearch(int start,int end){
        while(start<end){
            int absSum=Math.abs(list[start]+list[end]);
            if(absSum<minDiff){
                firstVal=list[start];
                secondVal=list[end];
                minDiff=absSum;
            }

            if(list[start]+list[end]==0) break;
            else if(list[start]+list[end]>0){
                --end;
            }
            else ++start;
        }
    }
    public static void main(String args[]) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st;

        int N = Integer.parseInt(br.readLine());
        st = new StringTokenizer(br.readLine());

        list = new int[N];
        for(int i=0;i<N;++i){
            list[i]=Integer.parseInt(st.nextToken());
        }

        binarySearch(0,N-1);

        bw.write(firstVal+" "+secondVal+"\n");
        bw.flush();
        bw.close();
    }
}

 

2. 우선순위 큐를 사용한 코드

import java.io.*;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

public class Main {

    static class Node implements Comparable<Node>{
        int sign;
        int number;

        public Node(int sign,int number){
            this.sign=sign;
            this.number=number;
        }
        @Override
        public int compareTo(Node o) {
            if(this.number<o.number) return -1;
            else return 1;
        }
    }

    static PriorityQueue<Node> q = new PriorityQueue<>();
    public static void main(String args[]) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st;

        int N = Integer.parseInt(br.readLine());
        st = new StringTokenizer(br.readLine());
        for(int i=0;i<N;++i){
            int num = Integer.parseInt(st.nextToken());
            int sign;

            if(num<0) sign=-1;
            else sign=1;

            Node node = new Node(sign, num*sign);
            q.offer(node);
        }

        int answer = (int)1e11;
        Node pre = q.poll();

        int first=0;
        int second=0;
        for(int i=1;i<N;++i){
            Node now = q.poll();
            int diff = Math.abs(now.number*now.sign+
                    pre.number*pre.sign);
            if(answer>diff){
                answer=diff;
                first=pre.number*pre.sign;
                second=now.number*now.sign;
                //System.out.println(first+" "+second);
            }
            answer = Math.min(answer,diff);
            pre=now;
        }

        if(first<second) bw.write(first+" "+second+"\n");
        else bw.write(second+" "+first+"\n");

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

 

이분 탐색을 사용했을 때 416ms, 우선순위 큐를 사용했을 때 496ms로

이분 탐색이 조금 더 빨랐다.