On this page
Binary Search & Variations
ค้นหาในข้อมูลที่เรียงแล้วด้วย O(log n) — และรูปแบบที่ดัดแปลงที่เจอบ่อย
binary search ค้นหาในข้อมูลที่เรียงแล้วโดยตัดครึ่งทุกครั้ง ทำให้เร็วมาก O(log n) (ข้อมูลล้านตัวใช้แค่ ~20 ครั้ง) เป็นเทคนิคที่เจอบ่อยและมีรูปแบบดัดแปลงหลายแบบ
binary search พื้นฐาน
def binary_search(arr, target):
lo, hi = 0, len(arr) - 1
while lo <= hi:
mid = (lo + hi) // 2
if arr[mid] == target:
return mid # เจอ คืน index
elif arr[mid] < target:
lo = mid + 1 # ตัดครึ่งซ้ายทิ้ง
else:
hi = mid - 1 # ตัดครึ่งขวาทิ้ง
return -1 # ไม่เจอ
print(binary_search([1, 3, 5, 7, 9], 7)) # 3binary search ใช้ได้กับข้อมูลที่เรียงแล้วเท่านั้น และระวังกับดัก off-by-one (lo <= hi, mid+1, mid-1) กับ infinite loop — เป็นจุดที่พลาดบ่อยสุด ลองไล่ทีละขั้นด้วยตัวอย่างเล็ก ๆ
bisect — binary search สำเร็จรูป
Python มีโมดูล bisect ที่ทำ binary search ให้ หา "ตำแหน่งที่ควรแทรก" เพื่อคงการเรียง
import bisect
arr = [1, 3, 5, 7, 9]
print(bisect.bisect_left(arr, 5)) # 2 (ตำแหน่งของ 5)
print(bisect.bisect_right(arr, 5)) # 3 (หลัง 5)
print(bisect.bisect_left(arr, 6)) # 3 (ตำแหน่งที่ควรแทรก 6)
bisect.insort(arr, 6) # แทรกแบบคงการเรียง
print(arr) # [1, 3, 5, 6, 7, 9]หา leftmost / rightmost
เมื่อมีค่าซ้ำ มักต้องหา "ตัวแรก" หรือ "ตัวสุดท้าย" ที่ตรงเงื่อนไข — ดัดแปลง binary search ด้วย bisect
import bisect
nums = [1, 2, 2, 2, 3]
# จำนวน 2 ทั้งหมด = ขอบขวา - ขอบซ้าย
left = bisect.bisect_left(nums, 2) # 1
right = bisect.bisect_right(nums, 2) # 4
print(right - left) # 3 (มี 2 อยู่ 3 ตัว)สรุปหัวข้อนี้
- binary search ตัดครึ่งทุกครั้ง O(log n) — ใช้กับข้อมูลเรียงแล้วเท่านั้น
- ระวัง off-by-one (lo<=hi, mid±1) และ infinite loop
- bisect: bisect_left/right หาตำแหน่ง, insort แทรกคงการเรียง
- หา leftmost/rightmost ด้วย bisect — นับค่าซ้ำได้
1) เขียน binary search เอง ทดสอบเคสเจอ/ไม่เจอ 2) ใช้ bisect หาตำแหน่งที่ควรแทรกค่า 3) นับจำนวนค่าที่ซ้ำด้วย bisect_left/right 4) อธิบายว่าทำไม binary search ต้องใช้ข้อมูลเรียงแล้ว