IT/์ปดํ“จํŒ…์  ์‚ฌ๊ณ 

์ด๋ถ„ ํƒ์ƒ‰๊ณผ Python์˜ bisect_left

Unused 2025. 3. 27. 20:31

์ด๋ถ„ ํƒ์ƒ‰ vs. ์ˆœ์ฐจ์  ํƒ์ƒ‰

์ด๋ถ„ ํƒ์ƒ‰(binary search)๋ž€, ์–ด๋–ค ๋ฐฐ์—ด๊ณผ ์ฐพ๊ณ ์ž ํ•˜๋Š” ์ˆ˜๊ฐ€ ์žˆ์„ ๋•Œ, ์ฐพ๊ณ ์ž ํ•˜๋Š” ๋ฒ”์œ„๋ฅผ ์ ˆ๋ฐ˜์”ฉ ์ขํ˜€๊ฐ€๋ฉฐ ๋น ๋ฅด๊ฒŒ ํ•ด๋‹น ๊ฐ’์˜ ์œ„์น˜๋ฅผ ์ฐพ์•„๋‚ด๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์ž…๋‹ˆ๋‹ค. ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ฌธ์ œ์—์„œ ์ž์ฃผ ๋“ฑ์žฅํ•˜๋Š” ๋Œ€ํ‘œ์ ์ธ ํƒ์ƒ‰ ๊ธฐ๋ฒ•์œผ๋กœ, ๋‹จ์ˆœํ•œ ์ •๋ ฌ ๋ฐฐ์—ด ํƒ์ƒ‰๋ถ€ํ„ฐ, ๊ฒฝ๊ณ„๊ฐ’ ์ฐพ๊ธฐ, ์‘์šฉ ๋ฌธ์ œ๊นŒ์ง€ ๋งค์šฐ ๋‹ค์–‘ํ•œ ํ˜•ํƒœ๋กœ ์ถœ์ œ๋ฉ๋‹ˆ๋‹ค. ๋งค ๋ฐ˜๋ณต๋งˆ๋‹ค ๊ฒ€์ƒ‰ ๋ฒ”์œ„๋ฅผ ์ ˆ๋ฐ˜์œผ๋กœ ์ค„์ด๊ธฐ์— O(log n)์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ๋‹ค๋งŒ, ๊ฐ’์˜ ๋Œ€์†Œ๋ฅผ ๋น„๊ตํ•˜๋ฉฐ ๋ฒ”์œ„๋ฅผ ์žก๊ธฐ์— ๋ฐฐ์—ด์ด ๋ฐ˜๋“œ์‹œ ์ •๋ ฌ๋จ์„ ์ „์ œ๋กœ ํ•ฉ๋‹ˆ๋‹ค.

๊ตฌํ˜„: ๋ฐ˜๋ณต vs. ์žฌ๊ท€

์ด๋ถ„ ํƒ์ƒ‰์€ ๋จผ์ € ์‹œ์ž‘ ์ธ๋ฑ์Šค์™€ ๋ ์ธ๋ฑ์Šค๋ฅผ ์žก๊ณ , ๊ทธ ๋‘˜์˜ ์ค‘๊ฐ„ (๋˜๋Š” ์•ˆ ๋‚˜๋ˆ ๋–จ์–ด์งˆ ๊ฒฝ์šฐ ํ•œ ์นธ ์™ผ์ชฝ) ์ธ๋ฑ์Šค๋ฅผ ์žก๋Š” ๊ฒƒ์œผ๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ •ํ™•ํ•œ ๊ฐ’์˜ ์ธ๋ฑ์Šค๋ฅผ ์ฐพ์„ ๋•Œ๊นŒ์ง€ ์‹œ์ž‘, ์ค‘๊ฐ„, ๋ ์ธ๋ฑ์Šค๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ๊ณ„์† ์กฐ์ •ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค. 

๋ฐ˜๋ณต์œผ๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ

๋ฐฑ๋ฌธ์ด ๋ถˆ์—ฌ์ผ๊ฒฌ, ๋ฐ˜๋ณต์œผ๋กœ ๊ตฌํ˜„๋œ Python ์ฝ”๋“œ๋ฅผ ๋ณด์‹œ๊ฒ ์Šต๋‹ˆ๋‹ค.

def binary_search_itr(arr, target): # arr: ์ „์ฒด ๋ฐฐ์—ด, target: ์ฐพ๊ณ ์ž ํ•˜๋Š” ๊ฐ’
    left = 0
    right = len(arr) - 1  # ๊ฒ€์ƒ‰ ๋ฒ”์œ„๋Š” [left, right]

    while left <= right:
        mid = (left + right) // 2

        if arr[mid] == target:
            return mid  # ๊ฐ’์„ ์ฐพ์•˜์œผ๋ฉด ํ•ด๋‹น ์ธ๋ฑ์Šค ๋ฐ˜ํ™˜
        elif arr[mid] < target:
            left = mid + 1  # ์˜ค๋ฅธ์ชฝ ๊ตฌ๊ฐ„์œผ๋กœ ์ด๋™
        else:
            right = mid - 1  # ์™ผ์ชฝ ๊ตฌ๊ฐ„์œผ๋กœ ์ด๋™

    return -1  # ๊ฐ’์„ ์ฐพ์ง€ ๋ชปํ–ˆ์„ ๊ฒฝ์šฐ

๊ฐ€๋ น, [1, 3, 4, 5, 7, 9, 11, 22, 33, 44, 55, 66]๋ผ๋Š” ๋ฐฐ์—ด์ด ์žˆ๊ณ , ์ฐพ๊ณ ์ž ํ•˜๋Š” ๊ฐ’์€ 22์ด๋ผ๊ณ  ๊ฐ€์ •ํ•˜์—ฌ, ์•„๋ž˜์™€ ๊ฐ™์ด ๋ฐ˜๋ณต๋ฌธ์„ ๋”ฐ๋ผ๊ฐ€๋ด…์‹œ๋‹ค.

๋ฐ˜๋ณต๋ฌธ ๋”ฐ๋ผ๊ฐ€๊ธฐ

๋ฐ˜๋ณต๋ฌธ์— ์ฒ˜์Œ ๋“ค์–ด์˜ค๋ฉด left=0, right=11์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  mid๋Š” (0+11)//2, ์ฆ‰ 5๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๊ณง 0๋ถ€ํ„ฐ 11๊นŒ์ง€์˜ ์ธ๋ฑ์Šค๋ฅผ ๋ฒ”์œ„๋กœ ์žก๊ณ , ๊ทธ ๊ฐ€์šด๋ฐ์˜ ์ˆซ์ž๋ฅผ target(=22)๊ณผ ๋น„๊ตํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. arr[5]=9์ด๋ฏ€๋กœ, 22๋ณด๋‹ค ์ž‘์Šต๋‹ˆ๋‹ค. ์ฆ‰ ์‹œ์ž‘์ ์ธ left ๊ฐ’์„ mid+1, ์ฆ‰ 6์œผ๋กœ ์กฐ์ •ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋ณต๋ฌธ ๋งˆ์ง€๋ง‰์— left, mid, right๋Š” ๊ฐ๊ฐ 6, 5, 11๋กœ ์กฐ์ •๋ฉ๋‹ˆ๋‹ค.

๋‘ ๋ฒˆ์งธ ๋ฐ˜๋ณต์—์„œ left=6, right=11๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  mid๋Š” (6+11)//2, ์ฆ‰ 8์ž…๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋งํ•ด, 6๋ถ€ํ„ฐ 11๊นŒ์ง€์˜ ์ธ๋ฑ์Šค๋ฅผ ๋ฒ”์œ„๋กœ ์žก๊ณ , ๊ทธ ๊ฐ€์šด๋ฐ์˜ ์ˆซ์ž๋ฅผ target(=22)๊ณผ ๋น„๊ตํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. arr[8]=33์ด๋ฏ€๋กœ, 22๋ณด๋‹ค ํฝ๋‹ˆ๋‹ค. ์ด๋ฒˆ์—๋Š” ๋์ ์ธ right๊ฐ’์„ mid-1, ์ฆ‰ 7๋กœ ์กฐ์ •ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋ณต๋ฌธ ๋งˆ์ง€๋ง‰์— left, mid, right๋Š” ๊ฐ๊ฐ 6, 8, 7๋กœ ์กฐ์ •๋ฉ๋‹ˆ๋‹ค.

์„ธ ๋ฒˆ์งธ ๋ฐ˜๋ณต์—์„œ left=6, right=7๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  mid๋Š” (6+7)//2, ์ฆ‰ 6์ž…๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋งํ•ด, 6๋ถ€ํ„ฐ 7๊นŒ์ง€์˜ ์ธ๋ฑ์Šค๋ฅผ ๋ฒ”์œ„๋กœ ์žก๊ณ , ๊ทธ ๊ฐ€์šด๋ฐ์˜ ์ˆซ์ž๋ฅผ target(=22)๊ณผ ๋น„๊ตํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. arr[6]=11์ด๋ฏ€๋กœ, 22๋ณด๋‹ค ์ž‘์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ์—๋Š” ์‹œ์ž‘์ ์ธ left ๊ฐ’์„ mid+1, ์ฆ‰ 7๋กœ ์กฐ์ •ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋ณต๋ฌธ ๋งˆ์ง€๋ง‰์— left, mid, right๋Š” ๊ฐ๊ฐ 7, 6, 7๋กœ ์กฐ์ •๋ฉ๋‹ˆ๋‹ค.   

๋„ค ๋ฒˆ์งธ ๋ฐ˜๋ณต์—์„œ๋„ ์œ„์™€ ๋™์ผํ•œ ๊ณผ์ •์œผ๋กœ, left=7, mid=7, right=7๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ์…‹ ๋‹ค ๊ฐ™์€ ๊ฐ’์ด๋‹ˆ `if arr[mid] == target` ์กฐ๊ฑด์— ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค. ๊ฐ’์„ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค. arr[7]=22. ์ด์ œ mid์˜ 7์„ ๋ฆฌํ„ดํ•จ์œผ๋กœ์จ ํ•จ์ˆ˜๊ฐ€ ์ข…๋ฃŒ๋ฉ๋‹ˆ๋‹ค.

์žฌ๊ท€๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ

์•„๋ž˜๋Š” ๋™์ผํ•œ ๊ธฐ๋Šฅ์„ ์žฌ๊ท€๋กœ ๊ตฌํ˜„ํ•œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

def binary_search_rcv(arr, target, left=0, right=None):
    if right is None:
        right = len(arr) - 1  # ์ตœ์ดˆ ํ˜ธ์ถœ ==> right ์ดˆ๊ธฐํ™”

    if left > right:
        return -1  # base case && ๊ฐ’์ด ์—†์Œ

    mid = (left + right) // 2

    if arr[mid] == target:
        return mid  # base case && ๊ฐ’์ด ์žˆ์Œ => ํ•ด๋‹น ์ธ๋ฑ์Šค ๋ฆฌํ„ด
    elif arr[mid] < target:
        return binary_search_rcv(arr, target, mid + 1, right)  # ์˜ค๋ฅธ์ชฝ ๊ตฌ๊ฐ„์—์„œ ์žฌ๊ท€
    else:
        return binary_search_rcv(arr, target, left, mid - 1)   # ์™ผ์ชฝ ๊ตฌ๊ฐ„์—์„œ ์žฌ๊ท€

์ด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ’€ ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐ”๋กœ ๋ฐฑ์ค€ 10815 "์ˆซ์ž ์นด๋“œ"์ž…๋‹ˆ๋‹ค. https://www.acmicpc.net/problem/10815

์ฐธ๊ณ ๋กœ ์•„๋ž˜๋Š” naive approach๋กœ ๊ตฌํ˜„ํ•œ ์ฝ”๋“œ์ธ๋ฐ, ํ˜น-์‹œ if in ๋ฌธ๋ฒ•์ด ๋‚˜๋ฆ„์˜ ์ตœ์ ํ™”๋ฅผ ๊ฑฐ์ณ์„œ ๋‹ต์„ ๋น ๋ฅด๊ฒŒ ์ฐพ์•„๋‚ด์ง€ ์•Š์„๊นŒ ํ–ˆ์œผ๋‚˜, ์‹œ๊ฐ„ ์ดˆ๊ณผ๊ฐ€ ๋‚ฉ๋‹ˆ๋‹ค.

import sys
input = sys.stdin.readline

cards_count = int(input())
cards_in_pkt = sorted(map(int,input().split()))
tests_count = int(input())
tests = list(map(int,input().split()))

result = [1 if a in cards_in_pkt else 0 for a in tests]
print(*result)

 

์‘์šฉ: ์ •ํ™•ํ•œ ๊ฐ’์ด ์—†์„ ๊ฒฝ์šฐ, '์ตœ์†Œ์˜ ์ตœ๋Œ€' ๋ฌธ์ œ

๊ฐ„ํ˜น ์ •ํ™•ํ•œ ํƒ€๊นƒ์ด ์ฃผ์–ด์ง€์ง€ ์•Š๋Š” ๋ฌธ์ œ๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ”๋กœ ๋ฐฑ์ค€ 2805 "๋‚˜๋ฌด ์ž๋ฅด๊ธฐ"์™€ ๊ฐ™์€ ๋ฌธ์ œ๋“ค์ž…๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰ ๋ฌธ๋‹จ์— ๋‚˜์˜จ ๋ฐ”์™€ ๊ฐ™์ด, "์ ์–ด๋„ M๋ฏธํ„ฐ๋ฅผ ๋ณด์žฅํ•˜๋Š” ์ ˆ๋‹จ๊ธฐ์˜ ๋†’์ด์˜ ์ตœ๋Œ“๊ฐ’"์„ ๊ตฌํ•˜๋Š” ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. ์ •ํ™•ํ•œ ํƒ€๊นƒ์„ ์ฐพ๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ๊ฐ€๋Šฅํ•œ ๊ฐ’ ์ค‘ ์ตœ๋Œ€๋ฅผ ๊ตฌํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ ์ด๋ถ„ ํƒ์ƒ‰์€ ์•„๋ž˜์™€ ๊ฐ™์ด ์‘์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

count, target_num = map(int,input().split())
trees = list(map(int,input().split()) )

low, high = 0, max(trees)

while low <= high:
    mid = (low + high) // 2
    sum_cut = sum((trees[i] - mid) for i in range(len(trees)) if trees[i] > mid)
    if sum_cut >= target_num: 
        low = mid + 1 # ๋” ๋งŽ๋‹ค ==> low๋ฅผ ๊ฐฑ์‹ 
    else:
        high = mid - 1 # ๋ชจ์ž๋ผ๋‹ค ==> high๋ฅผ ๊ฐฑ์‹ 

print(result)

์ด๋Š” ์ „ํ˜•์ ์ธ parametric search (ํŒŒ๋ผ๋ฉ”ํŠธ๋ฆญ ์„œ์น˜) ๋ฌธ์ œ๋กœ, ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ์ตœ๋Œ“๊ฐ’์„ ์ฐพ๋Š” 'upper bound' ํŒจํ„ด์ด๊ธฐ์— ์•„๋ž˜ ์„ค๋ช… ๋“œ๋ฆด `bisect_right`์™€ ๋™์ผํ•œ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

bisect_left vs. bisect_right

Python ๋‚ด์žฅ ๋ชจ๋“ˆ ์ค‘ `bisect`๋Š” ์ •๋ ฌ๋œ ๋ฆฌ์ŠคํŠธ์— ๊ฐ’์„ ์‚ฝ์ž…ํ•˜๊ฑฐ๋‚˜ ์œ„์น˜๋ฅผ ์ฐพ๋Š” ํ•จ์ˆ˜๋“ค์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋Œ€ํ‘œ์ ์œผ๋กœ๋Š” `bisect`, `bisect_left`, `bisect_right`๊ฐ€ ์žˆ๊ฒ ์Šต๋‹ˆ๋‹ค. 

ํ•ต์‹ฌ ํ•จ์ˆ˜ ๋น„๊ต

ํ•จ์ˆ˜ ๋ฐ˜ํ™˜ ์œ„์น˜ ์˜๋ฏธ
bisect_left(a, x) ์™ผ์ชฝ ์‚ฝ์ž… ์œ„์น˜ x๋ฅผ ๋„ฃ์„ ์ˆ˜ ์žˆ๋Š” ๊ฐ€์žฅ ์™ผ์ชฝ ์œ„์น˜
bisect_right(a, x) ๋˜๋Š” bisect(a, x) ์˜ค๋ฅธ์ชฝ ์‚ฝ์ž… ์œ„์น˜ x๋ฅผ ๋„ฃ์„ ์ˆ˜ ์žˆ๋Š” ๊ฐ€์žฅ ์˜ค๋ฅธ์ชฝ ์œ„์น˜

์ฐธ๊ณ : `bisect()`๋Š” `bisect_right()`์˜ alias, ์ฆ‰, ๊ฐ™์€ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ๋น„๊ตํ•ด๋ด…์‹œ๋‹ค.

def bs_by_bisect(arr,target_num):
    return (bisect_left(arr,target_num), bisect(arr,target_num), bisect_right(arr,target_num))
    
arr = [10, 20, 50, 66, 123, 214, 333, 444, 555, 777]
print("----------------------")
target_num = 49
print("target_num:",target_num, bs_by_bisect(arr,target_num))
target_num = 50
print("target_num:",target_num, bs_by_bisect(arr,target_num))
target_num = 51
print("target_num:",target_num, bs_by_bisect(arr,target_num))
print("----------------------")

๊ฒฐ๊ณผ๋Š” ์œ„์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

`bisect_left`๋Š” 49์™€ 50์—์„œ ์ธ๋ฑ์Šค 2, ์ฆ‰ 20์˜ ์œ„์น˜๋ฅผ ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  51์ด ๋˜์–ด์„œ์•ผ 50์˜ ์œ„์น˜๋ฅผ ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด `bisect_right`๋Š” 49์—์„œ๋งŒ 20์˜ ์œ„์น˜๋ฅผ ๋ฆฌํ„ดํ•˜๋ฉฐ, 50๋ถ€ํ„ฐ๋Š” ๋ฐ”๋กœ 50์˜ ์œ„์น˜๋ฅผ ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค.

๋” ๋‚˜์•„๊ฐ€๊ธฐ

์ง€๊ธˆ๊นŒ์ง€ ์ด๋ถ„ ํƒ์ƒ‰์˜ ๊ฐœ๋…์œผ๋กœ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์—ฌ `bisect_left`, `bisect_right` ๋“ฑ ์ด๋“ค์˜ ๊ฐœ๋…์„ ์‘์šฉํ•œ ์œ ํ˜•๊นŒ์ง€ ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” ๋ฐฑ์ค€ 11053 "๊ฐ€์žฅ ๊ธด ์ฆ๊ฐ€ํ•˜๋Š” ๋ถ€๋ถ„ ์ˆ˜์—ด"์ž…๋‹ˆ๋‹ค. ์ด๋ถ„ ํƒ์ƒ‰์„ ์‘์šฉํ•˜์—ฌ ์ง์ ‘ ๊ตฌํ˜„ํ•ด๋ณด์‹œ๊ธฐ๋ฅผ ์ถ”์ฒœ ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

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