Эрэмбэлэгдсэн array-д x-ээс багагүй хамгийн эхний тооны index-ийг Binary Search ашиглан олдог арга.
Эхлээд жижиг бодлого
Эрэмбэлэгдсэн a = [1, 3, 3, 5, 8] array-д 3-аас багагүй хамгийн эхний тоо хаана байна вэ? Хариу нь index 1.
Харин 4-ийг асуувал хариу 3 (тэнд 5 байна). 9-ийг асуувал бүх тоо 9-өөс бага тул хариу n = 5.
Энгийн аргаас санаа руу
Энгийн Binary Search тоо байгаа эсэхийг л хэлдэг. Ижил тоо олон байвал аль нэгийг нь олно. Гэтэл олон бодлогод "x хаанаас эхэлдэг вэ?", "x-ээс бага хэдэн тоо байна?" гэж асуудаг.
Lower Bound хүрээг [lo, hi) гэж хадгална. a[mid] >= x бол mid өөрөө хариу байж болох тул хаяхгүй: hi = mid. Үгүй бол mid болон түүнээс зүүн тийш бүх тоо хэт бага: lo = mid + 1. Хүрээ хоосон болоход lo нь хариу.
Нэр томьёо ба тэмдэглэгээ
- [lo, hi)
- lo хүрээнд орно, hi орохгүй. Эхэндээ
lo = 0,hi = n. - mid
- Хүрээний дунд:
(lo + hi) / 2.lo < hiүед mid нь hi-гаас үргэлж бага тул array-гээс гарахгүй. - lower_bound
- C++-ийн бэлэн function.
lower_bound(a, a + n, x) - aнь яг энэ кодын хариу.
a[i] ≥ 7 байх хамгийн эхний i-г хайна. Эхлээд lo = 0, hi = 10. hi нь array-н яг ард байна.
- Space тоглуулах
- ←→ алхам
- −+ хурд
- Энгийн
- mid
- Хариу (lo)
- Хайлтаас хасагдсан
Хамгийн эхнийх нь хаана?
Энэ array-д 7 гурван удаа байна. Тэдний хамгийн эхнийх нь хаана вэ? Lower Bound хариуг Binary Search ашиглан хурдан олно.
Дараа нь юу болох вэ?
Оноо 0 / 00дараалсан зөв, хамгийн их 0
Animation нэг алхам дээр зогсоно. Дараа нь код юу хийх вэ? Таагаад оноо цуглуул! Нэвтрэх хэрэггүй, оноо чинь энэ төхөөрөмж дээр хадгалагдана.
Юунд хэрэгтэй вэ?
"x хаанаас эхэлдэг вэ?", "x-ээс бага тоо хэд байна?" гэх мэт асуултад log n алхамд хариулах. C++-ийн lower_bound яг ингэж ажилладаг.
Яаж ажилладаг вэ?
1. Хайх хүрээ: lo = 0, hi = n (hi өөрөө хүрээнд орохгүй). 2. Дундах index: mid = (lo + hi) / 2. 3. a[mid] ≥ x бол хариу нь mid эсвэл түүнээс зүүн талд: hi = mid. 4. a[mid] < x бол хариу баруун талд: lo = mid + 1. 5. lo = hi болоход lo нь хариу. Ийм тоо байхгүй бол хариу n. Оролт: n, n ширхэг эрэмбэлэгдсэн тоо, дараа нь x.
Яагаад зөв, хэр хурдан бэ?
Loop-ын турш хоёр зүйл үнэн хэвээр байна: lo-гоос зүүн талын бүх тоо x-ээс бага, hi болон түүнээс баруун талын бүх тоо x-ээс багагүй. lo = hi болоход хариу яг тэр зааг дээр байна.
Алхам бүрт хүрээ хоёр дахин багасна. n = 1 000 000 бол 20 орчим алхам: хугацаа O(log n), нэмэлт санах ой O(1).
Түгээмэл алдаа
hi = mid - 1гэж бичвэл mid дээрх хариуг алдана.while (lo <= hi)гэж бичвэлlo = hiүедhi = midхүрээг багасгахгүй тул loop дуусахгүй.hi = n - 1гэж эхлүүлбэл бүх тоо x-ээс бага үед n гэсэн хариу гарч чадахгүй.- Эрэмбэлэгдээгүй array дээр хэрэглэх. Эхлээд
sort(a, a + n)хийнэ.
Хязгаарын тохиолдол
- Бүх тоо x-ээс бага: хариу n, өөрөөр хэлбэл array-н яг ард.
- Бүх тоо x-ээс багагүй: хариу 0.
- x олон удаа байгаа: хамгийн эхнийх нь index.
- n = 1: нэг алхмаар lo нь 0 эсвэл 1 болно.
Өөрийгөө шалга
a = [2, 4, 4, 7, 7, 7, 9, 12, 15, 20], x = 7. Хариу хэд вэ?Хариу харах
3.
Энэ array-д 7 хэдэн удаа байгааг Lower Bound-ыг хоёр удаа ашиглаж яаж олох вэ?
Хариу харах
x = 8 үеийн хариунаас x = 7 үеийн хариуг хасна: 6 − 3 = 3.
n = 1 000 000 бол loop хэдэн удаа ажиллах вэ?
Хариу харах
20 орчим.
2²⁰ ≈ 1 000 000.
Гурван дадлага
Hint-ээ нээхээс өмнө өөрөө оролдоорой.
1.
a = [1, 2, 2, 2, 5, 6], x = 2 үедlo,hi,midямар утга авахыг алхам алхмаар бич.Hint харах
Эхлээд
lo = 0,hi = 6.Хариу ба тайлбар
mid = 3: 2 ≥ 2,hi = 3.mid = 1: 2 ≥ 2,hi = 1.mid = 0: 1 < 2,lo = 1. Хариу 1.2.x-ээс их хамгийн эхний тооны index-ийг ол (Upper Bound).
Hint харах
Ганц тэмдэгт өөрчлөхөд хангалттай.
Хариу ба тайлбар
if (a[mid] > x)болгоно. C++-д энэ ньupper_bound.3.Q асуулт ирнэ: тус бүрд [L, R] хооронд хэдэн тоо байгааг ол (n, Q ≤ 10⁵).
Hint харах
Array-г эрэмбэлээд хоёр Lower Bound-ын зөрүүг ав.
Хариу ба тайлбар
Хариу нь
lower_bound(R + 1) - lower_bound(L). Асуулт бүр O(log n).
Жишээ
Оролт
10 2 4 4 7 7 7 9 12 15 20 7
Гаралт
3
Одоо өөрөө бодоод үз
Хичээл
Энэ сэдвийн хичээл удахгүй нэмэгдэнэ.