(10) BinarySearch

이분탐색의 시간복잡도는 O(logN)입니다.

middle을 업데이트하면서 target값 찾기

1

mid값이 아니므로, left와 rigth는 mid의 +-1로 업데이트합니다.

2

3

코테 문제

  • 문제 상황 : 오름차순으로 정렬된 배열에서 target값을 찾아야 합니다.

  • 제한 사항 : 알고리즘은 반드시 O(logn) 이어야 합니다.

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left = 0
        right = len(nums)-1
        
        # 예외처리
        if len(nums) ==1:
            if nums[0] == target:
                return 0
            else:
                return -1        
        
        while (left <= right):
            mid = (left + right)//2
            if target == nums[mid]:
                return mid
            elif target < nums[mid]:
                right = mid - 1
            else:
                left = mid + 1
        return -1


🍓 2. 입국심사

이진탐색을 문제에 적용하려면 우선, (1) left - right 범위 설정 (2) 중간값 검증 어떻게 할지 생각해야합니다!

  • 이분 탐색의 범위 설정

    최소시간과 최대시간 설정

    최대시간은 (가장 느린 심사관의 심사 시간) * (사람의 수)

  • 중간값 검증

    각 심사관의 (중간값//심사시간) 의 총합이 == 사람수

def solution(n, times):
    left, right = 1, max(times) * n

    def count(time):
        nums = 0
        for a in times:
            nums += time // a
        return nums

    answer = 0
    while left <= right:
        mid = (left + right) // 2
        counted = count(mid)
        if n == counted:
            answer = mid  # Save the result if the count matches
            right = mid - 1  # Still try to find a smaller value
        elif n < counted:
            right = mid - 1
        else:
            left = mid + 1

    # If no exact match is found, return the saved result or the left value
    return answer if answer else left


🍓 3. 징검다리 건너기 (Lv.3)

  • 문제 상황 : 니니지 친구들이 무제한으로 있을 때, 징검다리를 건널 수 있는 친구들의 최대 인원 수를 구하는 문제입니다. 징검다리 돌은 밟을 수 있는 숫자가 각각 정해져 있으며, 0이 되면 밝을 수 없고 다음 돌로 jump할 수 있습니다. jump 가능한 수는 k로 주어집니다.

  • 제한 사항 : 1<= stones의 배열의 길이, k <= 2*10^5

  • 문제 이해 : 0인 징검다리 돌이 k개 연속될 경우, 징검다리 건너기 종료! stones 배열의 길이가 매우 크므로 원소를 하나씩 차감해주면, 타임오버가 걸립니다.

  • 문제 접근 : 이진 탐색 O(logN)

(1) 나의 풀이 : 정확성 100, 효율성 0

처음에는, 원소를 하나씩 차감하면서, 연속으로 0인 돌이 k가 생기는지 확인하는 방식으로 코드를 짰습니다.

[나의 풀이 접기/펼치기]
def solution(stones, k):
    answer = 0
    cur = 0
    n = len(stones)
    
    while True:
        if cur == n:
            answer += 1
            cur = 0
        
        if stones[cur] != 0:
            stones[cur] -= 1
        
        else:
            nothing = True
            for i in range(1,k):
                if cur + i == n:
                    answer += 1
                    cur = -1
                    nothing = False
                    break

                if stones[cur+i] != 0:
                    cur += i
                    stones[cur] -= 1
                    nothing = False
                    break
            if nothing:
                break
        
        cur += 1
          
    return answer

(2) 이진탐색으로 풀기

O(nlongm), n: 디딤돌개수, m: 디딤돌의 최대값

# 최소/최대 idx를 가지고, 친구들의 수(M)를 찾기

def solution(stones, k):
    # 예외처리
    if k == 1:
        return min(stones)
    
    # M의 최소와 최대를 setting
    left = 1
    right = max(stones)
        
    # M이 답이라고 할 때, M-1에서 (k-1)개의 연속된 0이 있다. 
    def binaryCheck(mid):
        zeroCount = 0
        for v in stones:
            if v < mid:
                zeroCount += 1
            else:
                zeroCount = 0   # 연속되는 0만 의미가 있으므로
            if zeroCount >= k:  # k-1개까지 가능
                return False
        return True 
    
    while left < right-1 :
        mid = (left+right)//2
        if binaryCheck(mid):
            left = mid
        
        else:
            right = mid
            
    return left


Categories:

Updated:

Leave a comment