seungriyou / algorithm-study

μ•Œκ³ λ¦¬μ¦˜ & SQL 문제 풀이 기둝
https://leetcode.com/u/summer_y
0 stars 0 forks source link

[Algorithm] Binary Search 101 #98

Open seungriyou opened 3 months ago

seungriyou commented 3 months ago

References


이진 탐색(Binary Search)

μ–΄λ– ν•œ groupμ—μ„œ target을 찾으렀면, μ΅œμ•…μ˜ κ²½μš°μ—λŠ” λͺ¨λ“  μ›μ†Œλ₯Ό λ‹€ ν™•μΈν•¨μœΌλ‘œμ¨ O(n)에 μž‘μ—…μ„ μˆ˜ν–‰ν•˜κ²Œ λœλ‹€.

ν•˜μ§€λ§Œ μ›μ†Œλ“€μ΄ μ •λ ¬λ˜μ–΄ μžˆλ‹€λ©΄, search time을 O(logn)으둜 쀄일 수 μžˆλ‹€.

탐색 방법 λ³΅μž‘λ„
binary search $O(\log n)$
sequential search $O(n)$


이진 탐색 문제 풀이 μ‹œ κ³ λ €ν•΄μ•Ό ν•˜λŠ” μ„Έ 가지

  1. 루프 νƒˆμΆœ 쑰건
  2. 경계 λ³€μˆ˜ lo와 hi의 μ΄ˆκΈ°κ°’
  3. 경계 μΆ•μ†Œ 방법


풀이 원칙

  1. lo & hiλ₯Ό μ΄ˆκΈ°ν™”ν•  λ•ŒλŠ” κ°€λŠ₯ν•œ λͺ¨λ“  μ •λ‹΅ λ²”μœ„λ₯Ό ν¬ν•¨ν•˜λ„λ‘ ν•œλ‹€.

    일반적으둜 λ°°μ—΄μ˜ μ›μ†Œμ—μ„œ target을 μ°ΎλŠ” 경우, lo와 hiλŠ” λ°°μ—΄μ˜ 인덱슀의 λ²”μœ„μ™€ κ°™λ‹€.

    lo = 0
    hi = len(nums) - 1

    ν•˜μ§€λ§Œ 배열에 target μ›μ†Œλ₯Ό λΌμ›Œλ„£λŠ” λ“± νŠΉμˆ˜ν•œ κ²½μš°μ—λŠ” λ‹€μŒκ³Ό 같이 hiλ₯Ό ν•˜λ‚˜ 더 κ³ λ €ν•΄μ•Ό ν•œλ‹€.

    ex. 69. Sqrt(x) / 35. Search Insert Position

    lo = 0
    hi = len(nums)
  2. mid 계산 μ‹œ μ˜€λ²„ν”Œλ‘œμš°μ™€ lower/upper mid 에 μ£Όμ˜ν•œλ‹€.

    1. μ˜€λ²„ν”Œλ‘œμš°κ°€ μΌμ–΄λ‚˜μ§€ μ•Šλ„λ‘ ν•œλ‹€.

      int overflowκ°€ μ—†λŠ” Python은 상관 μ—†λ‹€κ³  μ•Œκ³ μžˆμœΌλ‚˜, lower/upper midλ₯Ό μ΄μš©ν•˜λ €λ©΄ 두 번째 방법이 μ‰¬μ›Œλ³΄μΈλ‹€.

      # worst
      mid = (lo + hi) // 2
      
      # much better, but still possible
      mid = lo + (hi - lo) // 2
      
      # best
      mid = (lo + hi) >> 1
    2. lower/upper mid 쀑 μ μ ˆν•œ 것을 μ„ νƒν•œλ‹€. 잘λͺ» μ„ νƒν•˜λ©΄ λ¬΄ν•œ 루프에 빠질 수 μžˆλ‹€.

      β†’ 5λ²ˆμ—μ„œ μžμ„Ένžˆ 닀룬닀.

      # lower(left) mid
      mid = lo + (hi - lo) // 2
      
      # upper(right) mid
      mid = lo + (hi - lo + 1) // 2
  3. 경계λ₯Ό μΆ•μ†Œν•΄λ‚˜κ°ˆ λ•Œ, midλ₯Ό μ œμ™Έν•˜λŠ” λ‘œμ§μ„ μ‚¬μš©ν•œλ‹€.

    λ‹¨μˆœν•œ 논리λ₯Ό μœ„ν•΄ 단일 쌍의 if ... elseλ₯Ό μ‚¬μš©ν•˜λ©°, 항상 midλ₯Ό μ œμ™Έν•˜λŠ” λ‘œμ§μ„ μ‚¬μš©ν•œλ‹€.

    개인적인 κ²¬ν•΄λ‘œλŠ”, midλ₯Ό μ œμ™Έν•˜λŠ” 둜직과 ν¬ν•¨ν•˜λŠ” 둜직 쀑 더 직관적인 λ‘œμ§μ„ μ‚¬μš©ν•˜λŠ” 편이 쒋은 것 κ°™λ‹€.

    if target < nums[mid]:
        hi = mid - 1 # mid is excluded
    else:
        lo = mid # mid is included
    if target > nums[mid]:
        lo = mid + 1 # mid is excluded
    else:
        hi = mid # mid is included
  4. while 문의 쑰건은 항상 lo < hi 둜 ν•˜λŠ” 것이 κ°„λ‹¨ν•˜λ‹€.

    while lo < hi: 루프가 μ’…λ£Œλ˜λŠ” μœ μΌν•œ 쑰건은 lo == hi이며, lo와 hiκ°€ 같은 μš”μ†Œλ₯Ό 가리킬 κ²ƒμ΄λΌλŠ” 것을 μ•Œκ³  μžˆμœΌλ―€λ‘œ lo < hiλ₯Ό μ±„νƒν•œλ‹€.

    ν•˜μ§€λ§Œ lo <= hiκ°€ 더 직관적인 κ²½μš°κ°€ μžˆμœΌλ―€λ‘œ, λ•Œμ— 따라 μ μ ˆν•˜κ²Œ μ μš©ν•˜μž.

    ex. 162. Find Peak Element, 1901. Find a Peak Element II

  5. λ¬΄ν•œ 루프λ₯Ό ν”Όν•˜κΈ° μœ„ν•΄μ„œλŠ” 2개의 μ›μ†Œκ°€ λ‚¨μ•˜μ„ λ•Œλ₯Ό κ³ λ €ν•΄μ•Ό ν•œλ‹€.

    lower / upper midλ₯Ό 잘λͺ» μ„ νƒν•˜λ©΄ λ£¨ν”„μ—μ„œ 아무 μ—…λ°μ΄νŠΈλ„ μΌμ–΄λ‚˜μ§€ μ•Šμ„ 수 있고(= μΆ•μ†Œκ°€ μΌμ–΄λ‚˜μ§€ X), μ΄λŠ” 곧 λ¬΄ν•œ 루프에 λΉ μ§€κ²Œ λœλ‹€.

    ν”„λ‘œκ·Έλž¨μ΄ λ¬΄ν•œ 루프에 λΉ μ‘Œλ‹€λ©΄ lo와 hi둜 μ„€μ •λœ 경계 내뢀에 두 개의 μš”μ†Œλ§Œ λ‚¨μ•˜μ„ λ•Œλ₯Ό 생각해야 ν•œλ‹€.

    • lower midλ₯Ό μ‚¬μš©ν•˜λŠ” λ‹€μŒμ˜ μ½”λ“œλŠ” 두 개의 μ›μ†Œλ§Œ λ‚¨μ•˜μ„ λ•Œ 아무것도 ν•˜μ§€ μ•Šμ•„(= μžκΈ°μžμ‹ μœΌλ‘œ μΆ•μ†Œ) λ¬΄ν•œ 루프에 λΉ μ§€κ²Œ λœλ‹€. μ΄λŸ¬ν•œ μ½”λ“œμ—μ„œλŠ” upper midλ₯Ό μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.

      mid = lo + (hi - lo) // 2 # lower mid
      
      if target < nums[mid]:
          hi = mid - 1
      else:
          lo = mid
    • λ°˜λŒ€λ‘œ, upper midλ₯Ό μ‚¬μš©ν•˜λŠ” λ‹€μŒμ˜ μ½”λ“œλŠ” λ˜ν•œ λ¬΄ν•œ 루프에 λΉ μ§€κ²Œ λœλ‹€. μ΄λŸ¬ν•œ μ½”λ“œμ—μ„œλŠ” lower midλ₯Ό μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.

      mid = lo + (hi - lo + 1) // 2 # upper mid
      
      if target > nums[mid]:
          lo = mid + 1
      else:
          hi = mid

    704. Binary Search 문제λ₯Ό λ‹€μŒκ³Ό 같이 두 가지 midλ₯Ό λͺ¨λ‘ μ‚¬μš©ν•˜μ—¬ ν’€ 수 μžˆλ‹€.

    midλ₯Ό μ„ νƒν•˜λŠ” 것과 경계 μΆ•μ†Œ λ‘œμ§μ€ 항상 ν•¨κ»˜ μˆ˜ν–‰λ˜μ–΄μ•Ό ν•˜λ©°, μ΄λ•Œλ§ˆλ‹€ μ΅œμ†Œ 1개의 μ›μ†Œκ°€ μ œμ™Έλ˜μ–΄μ•Ό 함을 λͺ…μ‹¬ν•œλ‹€.


κ°€μž₯ 일반적인 ν…œν”Œλ¦Ώ

Minimize k, s.t. condition(k) is True

while loop λ‚΄μ˜ if λ¬Έμ—μ„œ λΉ„κ΅μ—°μ‚°μžλ₯Ό μ΄μš©ν•΄μ„œ νŒλ‹¨ν•΄λ„ λ˜μ§€λ§Œ, condition() ν•¨μˆ˜ μ•ˆμ—μ„œ boolean κ°’μœΌλ‘œ νŒλ‹¨ν•΄μ„œ λ°˜ν™˜ν•˜λ©΄ 더 κΉ”λ”ν•˜λ‹€!

단, λ‘œμ§μ„ μ„€κ³„ν•˜κΈ° μ–΄λ €μšΈ 수 μžˆμœΌλ‹ˆ μš°μ„  if λ¬Έμ—μ„œ λΉ„κ΅μ—°μ‚°μžλ₯Ό μ΄μš©ν•˜λŠ” 것도 쒋을 것 κ°™λ‹€.

def binary_search(array) -> int:
    def condition(value) -> bool:
        pass

    left, right = 0, len(array)
    while left < right:
        mid = left + (right - left) // 2
        if condition(mid):
            right = mid
        else:
            left = mid + 1
    return left

[!caution] condition ν•¨μˆ˜λ₯Ό μ–΄λ–»κ²Œ 섀계해야 ν•˜κ³ , 이λ₯Ό λ§Œμ‘±ν•˜λŠ” κ°’ 쀑 μ–΄λ–€ 값을 μ°Ύμ•„μ•Ό ν•˜λŠ”μ§€λ₯Ό 잘 생각해야 ν•œλ‹€.

(특히 k-th μ›μ†Œλ₯Ό μ°ΎλŠ” λ¬Έμ œμ™€ 같이 직관적이지 μ•Šμ€ 경우...)

seungriyou commented 3 months ago

Related Problems