Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

우당탕탕 개발일지

[프로그래머스] 이진 탐색(Binary Search) 본문

알고리즘

[프로그래머스] 이진 탐색(Binary Search)

YUDENG 2024. 12. 13. 15:31

이진 탐색이란?

 

이분 탐색이라고도 불리는 이진 탐색은 정렬된 데이터에서 특정 값을 찾는 탐색 알고리즘이다.

탐색 범위를 절반씩 줄여가며 값을 찾기 때문에 시간 복잡도가 O(logn)으로 빠른 탐색이 가능하다.

 

Binary Search
import java.io.*;
import java.util.*;

public class Main {
    static final BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static int[] arr;

    static boolean binarySearch(int target) {
        int left = 0;
        int right = arr.length - 1;

        while (left <= right) {
            // 중간값
            int mid = left + (right - left) / 2;
            
            if (arr[mid] == target) {
                return true;
            } else if (arr[mid] < target) {
                left = mid + 1; // 오른쪽 범위 탐색
            } else {
                right = mid - 1; // 왼쪽 범위 탐색
            }
        }

        return false; // 값을 찾지 못함
    }
}

 

탐색 범위의 중간값을 선택하기 위해서는 배열이 정렬되어 있어야 한다. 찾고자 하는 값이 중간값보다 작을 경우 중간값의 왼쪽을, 클 경우 오른쪽을 탐색한다. 탐색 범위를 계속 절반으로 줄이며 탐색하며, 찾는 값이 중간값과 일치하면 탐색이 종료된다.

 

중간값 수식에서 left + (right - left) / 2 을 한 이유는 큰 값 기준으로 mid를 구할 경우, 오버플로우를 방지하기 위해서이다.

 

import java.util.*;

class Solution {
    public int solution(int[] diffs, int[] times, long limit) {
        int level = 0;
        long time = limit + 1;
        
        while(time > limit){
            level++; // 숙련도 증가
            time = getLevel(diffs, times, level);
        }
        return level;
    }
    
    static long getLevel(int[] diffs, int[] times, int level){
        
        long time = 0;
        
        time += getTime(diffs[0], times[0], times[0], level);
        
        for(int i = 1; i < diffs.length; i++){
            time += getTime(diffs[i], times[i], times[i-1], level);
        }
        
        return time;
    }
    
    static long getTime(int diff, int time_cur, int time_prev, int level){
        if(diff <= level) {
            return time_cur;
        } else {
            int n = diff - level;
            return (time_cur + time_prev) * n + time_cur;
        }
    }
}

 

 

[ 프로그래머스 ] 퍼즐 게임 챌린지

https://school.programmers.co.kr/learn/courses/30/lessons/340212

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

 

처음에 푼 방식은 브루트포스 방식으로 숙련도(=level)을 1부터 시작하여 제한시간(=limit)보다 소요되는 시간이 적은 숙련도가 나올 때까지 탐색을 시작한다. 당연하게도 숙련도가 증가할 수록, 시간복잡도가 커지게 되므로 시간 초과가 발생한다.

 

브루트포스 풀이 (시간초과)
import java.util.*;

class Solution {
    public int solution(int[] diffs, int[] times, long limit) {
        int level = 0;
        long time = limit + 1;
        
        while(time > limit){
            level++; // 숙련도 증가
            time = getLevel(diffs, times, level);
        }
        return level;
    }
    
    static long getLevel(int[] diffs, int[] times, int level){
        
        long time = 0;
        
        // 첫 번째
        time += getTime(diffs[0], times[0], times[0], level);
        
        for(int i = 1; i < diffs.length; i++){
            time += getTime(diffs[i], times[i], times[i-1], level);
        }
        
        return time;
    }
    
    static long getTime(int diff, int time_cur, int time_prev, int level){
        if(diff <= level) {
            return time_cur;
        } else {
            int n = diff - level;
            return (time_cur + time_prev) * n + time_cur;
        }
    }
}

 

 

이진탐색으로 풀면 시간 초과가 발생하지 않는다.

여기서 주의할 점은 초기 left를 0으로 지정 후 코드를 실행하면, 테스트 14에서 오류가 발생한다.

 

이진 탐색 풀이
import java.util.*;

class Solution {
    public int solution(int[] diffs, int[] times, long limit) {
        int left = 1, right = Integer.MAX_VALUE;
        int answer = 0;
        
        while(left <= right){
            int mid = left + (right - left) / 2;
            long time = getLevel(diffs, times, mid);
            
            if (time <= limit) {
                answer = mid;
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        
        return answer;
    }
    
    static long getLevel(int[] diffs, int[] times, int level){
        
        long time = 0;
        
        // 첫 번째
        time += getTime(diffs[0], times[0], times[0], level);
        
        for(int i = 1; i < diffs.length; i++){
            time += getTime(diffs[i], times[i], times[i-1], level);
        }
        
        return time;
    }
    
    static long getTime(int diff, int time_cur, int time_prev, int level){
        if(diff <= level) {
            return time_cur;
        } else {
            int n = diff - level;
            return (time_cur + time_prev) * n + time_cur;
        }
    }
}

 

 

728x90

'알고리즘' 카테고리의 다른 글

[BOJ] 유클리드 호제법  (0) 2024.12.20
[BOJ] 우선선위 큐 (Priority Queue) & TreeMap  (0) 2024.12.05
[BOJ] 플로이드 워셜  (0) 2024.12.03