Asosiy qismga o‘tish

4. Ikkilik qidiruv

Nazariya

Fikr

Saralangan massivda o‘rtadagi elementga qaraymiz. Agar u izlanayotgan
sondan katta bo‘lsa, javob chap yarmida; kichik bo‘lsa — **o‘ng
yarmida**. Har qadamda qidiruv sohasi ikki barobar kichrayadi.

10⁹ ta element ichidan topish uchun atigi ~30 qadam kerak.

Yozuvi

def topish(a, x):
    chap, ong = 0, len(a) - 1
    while chap <= ong:
        orta = (chap + ong) // 2
        if a[orta] == x:
            return orta
        if a[orta] < x:
            chap = orta + 1
        else:
            ong = orta - 1
    return -1

Shart saralanganlik. Saralanmagan massivda ikkilik qidiruv
noto‘g‘ri javob beradi — bu eng ko‘p uchraydigan xato.

Tayyor vosita

import bisect
i = bisect.bisect_left(a, x)    # x ni qo‘yish mumkin bo‘lgan eng chap joy
j = bisect.bisect_right(a, x)   # eng o‘ng joy
soni = j - i                    # x nechta marta uchraydi

Javob bo‘yicha ikkilik qidiruv

Ba’zan massiv yo‘q, lekin javobning o‘zini qidirish mumkin. Buning
uchun «X javob bo‘la oladimi?» degan savolga «ha» yoki «yo‘q» deb javob
beradigan funksiya yoziladi — quyida u boladimi(x). Bu tayyor funksiya
emas: har bir masalada uni o‘zingiz, shu masala shartiga qarab yozasiz.

Usul ishlashi uchun tekshiruv monoton bo‘lishi shart: agar X uchun
«ha» bo‘lsa, X dan katta har qanday son uchun ham «ha». Ya’ni sonlar
bo‘ylab javoblar shunday joylashadi:

x:         1    2    3    4    5    6   ...
boladimi:  yo‘q yo‘q yo‘q ha   ha   ha  ...

Biz birinchi «ha» ni — eng kichik yetarli qiymatni — qidiramiz.

Misol. n berilgan (1 ≤ n ≤ 10¹⁸). x² ≥ n bo‘ladigan eng kichik
natural x ni toping. Bu yerda tekshiruv — x * x >= n: 4 uchun
bajarilsa, 5, 6, … uchun ham albatta bajariladi, ya’ni monoton.

n = int(input())


def boladimi(x):
    # x javob bo‘la oladimi: x² n dan kichik emasmi?
    return x * x >= n


chap, ong = 1, 10**9      # javob shu oraliqda: 10⁹ · 10⁹ = 10¹⁸ ≥ n
while chap < ong:
    orta = (chap + ong) // 2
    if boladimi(orta):
        ong = orta        # orta ham javob bo‘lishi mumkin — uni tashlamaymiz
    else:
        chap = orta + 1   # orta javob emas — undan kattalariga o‘tamiz
print(chap)

n = 10 bo‘lsa: 3² = 9 < 10, 4² = 16 ≥ 10 — javob 4. Taxminan 30
qadamda topiladi, holbuki 1 dan boshlab sanab chiqish 10⁹ qadamgacha
cho‘zilishi mumkin.

Ikkita qoida:

  • ong — tekshiruv albatta «ha» bo‘ladigan qiymat bo‘lsin, aks holda

javob oraliqdan tashqarida qolib ketadi;

  • tekshiruv teskari bo‘lsa («X uchun «ha» bo‘lsa, kichiklari uchun ham»),

eng katta mos qiymat qidiriladi va shartlar almashtiriladi.

Bu usul bilan «eng kam vaqt», «eng kichik sig‘im», «eng katta
masofa» turidagi masalalar yechiladi.

Cheksiz sikldan ehtiyot bo‘ling

chap < ong va orta = (chap + ong) // 2 bilan chap = orta yozsangiz,
sikl qotib qoladi. Chegaralarni har doim kamida bir birlikka
siljiting.

Misol

import bisect
a = sorted(map(int, input().split()))
x = int(input())
i = bisect.bisect_left(a, x)
print(i + 1 if i < len(a) and a[i] == x else -1)

Mashq masalalari

✓KodMasalaQiyinlik
AL04-1 Kichiklar soni Boshlang‘ich
AL04-2 Oraliqdagi sonlar Oson
AL04-3 Butun ildiz Oson
AL04-4 O‘tin kesish O‘rta
AL04-5 Minoralar Qiyin
B103 Ikkilik qidiruv O‘rta

Nazorat savollari

1 Ikkilik qidiruv ishlashi uchun massiv qanday bo‘lishi kerak? Bitta to‘g‘ri javob
2 10⁶ ta element ichida ikkilik qidiruv taxminan necha qadam qiladi? Bitta to‘g‘ri javob
3 Saralanmagan massivda ikkilik qidiruv sekin, lekin baribir to‘g‘ri javob beradi. To‘g‘ri yoki noto‘g‘ri
4 O‘rtani hisoblash uchun bo‘sh joyga nima yoziladi? Bo‘sh joyni to‘ldirish
orta = (chap + ong) ____ 2
5 Nima chiqadi? Kod nima chiqaradi
import bisect
a = [1, 3, 5, 7]
print(bisect.bisect_left(a, 5))
6 «Javob bo‘yicha ikkilik qidiruv» qachon ishlatiladi? Bir nechta to‘g‘ri javob

Bir nechta javob to‘g‘ri bo‘lishi mumkin.

7 `bisect_right(a, x) - bisect_left(a, x)` nimani beradi? Qisqa javob — yoziladi
8 a = [1, 3, 5, 7, 9], x = 4. Qidiruv necha qadamdan keyin −1 qaytaradi? Kod nima chiqaradi
# chap=0, ong=4 dan boshlanadi
# har qadamda soha ikkiga bo'linadi
9 `chap = orta` deb yozish cheksiz siklga olib kelishi mumkin. To‘g‘ri yoki noto‘g‘ri
10 Ikkilik qidiruvning murakkabligi qanday? Bitta to‘g‘ri javob

Javoblar serverda tekshiriladi. Katta-kichik harf, apostrof shakli va ortiqcha bo‘shliq ahamiyatsiz.