يؤدي البحث الثنائي إلى تقليل مساحة البحث إلى النصف في كل خطوة. في مصفوفة مرتبة من عناصر n، يتم العثور على هدف في وقت O(log n).
def binary_search(nums, target):
lo, hi = 0, len(nums) - 1
while lo <= hi:
mid = (lo + hi) // 2
if nums[mid] == target:
return mid
elif nums[mid] < target:
lo = mid + 1
else:
hi = mid - 1
return -1
بسيطة - ولكن القوة الحقيقية للبحث الثنائي تذهب إلى ما هو أبعد من المصفوفات المصنفة.
يعمل البحث الثنائي عندما يكون لديك حالة رتيبة عبر نطاق ما. لا يلزم وجود "المصفوفة" - فأنت تحتاج فقط إلى نطاق [lo, hi] ووظيفة تنقلب من False إلى True (أو العكس) عند بعض الحدود.
Search space: [lo .................. hi]
Condition: F F F F T T T T
^-- answer
بدلاً من البحث في مصفوفة، ابحث في مساحة الإجابة. اسأل: "هل يمكنني تحقيق النتيجة X؟" إذا كانت الإجابة بنعم، حاول أصغر. إذا كان الجواب لا، حاول أكبر.
لدى كوكو n أكوام من الموز وh ساعة. ابحث عن الحد الأدنى لسرعة تناول الطعام حتى تنتهي في الوقت المناسب.
def min_speed(piles, h):
lo, hi = 1, max(piles)
while lo < hi:
mid = (lo + hi) // 2
hours = sum((p + mid - 1) // mid for p in piles)
if hours <= h:
hi = mid # speed works, try slower
else:
lo = mid + 1 # too slow, go faster
return lo
مساحة الإجابة هي [1, max(piles)] والحالة رتيبة - السرعة الأعلى تعني دائمًا ساعات أقل.
تسجيل الدخول للانضمام إلى النقاش
تم تدوير مصفوفة مرتبة عند نقطة محورية: [4, 5, 6, 7, 0, 1, 2]. يتم فرز النصف دائمًا. قارن mid مع lo لتحديد النصف، ثم تحقق مما إذا كان الهدف يقع في النصف الذي تم فرزه.
[4, 5, 6, 7, 0, 1, 2]
L M R
Left half [4..7] is sorted.
Target 1 not in [4..7] → search right.
في مصفوفة مرتبة تم تدويرها [3،4،5،1،2]، أي نصف يتم فرزه عندما يكون المنتصف = 2 (القيمة 5)؟
##الحدث الأول والأخير
للعثور على الحدث الأول، عندما تصل إلى الهدف، لا تتوقف - اضبط hi = mid واستمر في البحث إلى اليسار. بالنسبة إلى الأخير، اضبط lo = mid + 1 وابحث يمينًا.
يمنحك هذا الزوج من عمليات البحث أيضًا العدد للهدف: last - first + 1.
عنصر أكبر من كلا الجيران. حتى في المصفوفة غير المصنفة، يعمل البحث الثنائي: إذا كانت nums[mid] < nums[mid + 1]، تكون الذروة على اليمين؛ وإلا فإنه على اليسار. يا (سجل ن).
إذا تم فرز الصفوف وكان العنصر الأول في كل صف أكبر من العنصر الأخير في السابق، فتعامل مع المصفوفة كمصفوفة مرتبة واحدة من عناصر m × n. فهرس الخريطة k إلى الصف k // n، العمود k % n.
أوجد أكبر عدد صحيح x حيث x * x ≤ n. مساحة البحث: [0, n]. البحث الثنائي الكلاسيكي عن الإجابة.
def sqrt(n):
lo, hi = 0, n
while lo <= hi:
mid = (lo + hi) // 2
if mid * mid <= n:
lo = mid + 1
else:
hi = mid - 1
return hi
تطلب منك مشكلات مثل "تقسيم المصفوفة الأكبر حجمًا" أو "القدرة على شحن الطرود خلال D من الأيام" تقليل أسوأ الحالات. الجواب رتيب: إذا كانت القدرة C تعمل، فإن C+1 تعمل أيضًا. البحث الثنائي على C.
بالنسبة لـ ”القدرة على شحن الطرود في أيام D”، ما هي مساحة البحث للبحث الثنائي؟
lo, hi = min_possible, max_possible
while lo < hi:
mid = (lo + hi) // 2
if condition(mid):
hi = mid # mid works, try smaller
else:
lo = mid + 1 # mid fails, need larger
return lo
اضبط hi = mid مقابل lo = mid اعتمادًا على ما إذا كنت تبحث عن صحيح الأول أو صحيح الأخير.
ما هو التعقيد الزمني للبحث الثنائي في مساحة إجابة بالحجم S مع فحص جدوى O(n)؟