IlmHamroh
JavaScript Full-stack/14-qism. Algoritmlar va ma'lumotlar tuzilmalari56/60-dars20 daqiqa
Mundarija (32)

Masala yechish jarayoni: UMPIRE, avval brute force, keyin optimallashtirish

Qisqacha: Notanish masalada qotib qolmaslik uchun tizimli jarayon kerak. UMPIRE — oltita qadam: masalani tushunish (Understand), tanish naqshga moslash (Match), reja (Plan), kod (Implement), qo'lda tekshirish (Review) va baholash (Evaluate). Eng muhim odat — avval brute force yechim yozish: u sekin, lekin to'g'ri va keyingi tez yechimlar shu bilan tekshiriladi. Optimallashtirish ko'pincha xotira evaziga vaqt yutishdir — tanlovni ongli qiling.

Bu darsda

  • UMPIRE ning olti qadamini bitta «Bahor» masalasida boshidan oxirigacha bajarasiz.
  • Masalani tushunish uchun to'g'ri savollar berasiz va kichik misollar jadvalini tuzasiz.
  • Avval brute force yozib, keyin uni ikki xil usulda optimallashtirasiz va uchalasini o'lchab solishtirasiz.
  • Vaqt va xotira o'rtasidagi tanlovni vaziyatga qarab asoslay olasiz.

Oldin bilishingiz kerak: Muammo yechish metodikasi, Ikki ko'rsatkich (two pointers), Hash map bilan hisoblash naqshlari, Intervallar va sweep line.

1. Nega bu kerak?

Ellik beshta algoritm darsi ortda qoldi. Endi Sardorning qo'lida ko'p asbob bor: ikki ko'rsatkich, suriluvchi oyna, hash map, heap, graf, DP. Lekin bir kuni Jasur aka yangi masala berdi va Sardor yarim soat ekranga tikilib o'tirdi. Qaysi asbobni olishni bilmadi, kodni boshlab, o'chirdi, yana boshladi.

Bu holat hammada bo'ladi — tajribali dasturchilarda ham. Farq shundaki, tajribali dasturchi jarayonga tayanadi. U birdaniga "aqlli" yechimni qidirmaydi. Avval masalani to'liq tushunadi, keyin eng sodda yechimni yozadi, so'ng uni yaxshilaydi. Bu xuddi oshpazga o'xshaydi: yangi taomni pishirishdan oldin retseptni oxirigacha o'qiydi, masalliqni tayyorlaydi, keyin olovni yoqadi.

Muammo yechish metodikasi darsida Polya'ning to'rt qadamini o'rgangan edik: tushunish, reja, bajarish, ortga qarash. Bugun uni algoritmlar uchun kengaytiramiz. Endi "reja" ichida tanish naqshni izlash bor, "ortga qarash" ichida esa Big-O va o'lchov.

2. UMPIRE: olti qadam

UMPIRE — dasturlash ta'limi bilan shug'ullanadigan CodePath tashkilotida mashhur bo'lgan jarayon nomi. Har harf bitta qadam:

flowchart LR
  U["U — tushun<br/>savol, misol"] --> M["M — moslashtir<br/>tanish naqsh"]
  M --> P["P — reja<br/>avval brute force"]
  P --> I["I — kod"]
  I --> R["R — qo'lda tekshir"]
  R --> E["E — baholash<br/>Big-O, o'lchov"]
  E -. "sekin bo'lsa" .-> M

Diagrammada oxirgi o'q orqaga qaytadi. Brute force yechim tayyor bo'lgach, baholash "sekin" desa, Match qadamiga qaytamiz va yaxshiroq naqsh izlaymiz. Bu aylana bir necha marta takrorlanishi mumkin. Har aylanishda qo'lingizda ishlaydigan va tekshirilgan yechim bo'ladi.

Bugun UMPIRE ni bitta masalada qadamma-qadam bajaramiz.

Masala. «Bahor» sovg'a kartalari sotmoqchi. Karta 100 000 so'mlik va qoidasi bor: aynan ikki xil taom olinadi, ularning narxi yig'indisi kartaga teng bo'lishi kerak. Sayt mehmonga menyudan shunday juftni topib berishi kerak.

3. U — tushunish

3.1 Savollar

Masala shartidagi har so'z bir nechta ma'noga ega bo'lishi mumkin. Kod yozishdan oldin noaniqliklarni yopamiz. Intervyuda bu savollarni intervyuerga beriladi, ishda — vazifani bergan odamga. Sardor Jasur akadan so'radi:

Savol Javob
Bitta taomni ikki marta olish mumkinmi? Yo'q, ikki xil taom
Ikki taomning narxi bir xil bo'lishi mumkinmi? Ha, manti va chuchvara ikkalasi 30 000
Bir nechta juft bo'lsa-chi? Istalgan bittasi yetadi
Juft bo'lmasa nima qaytaramiz? null — sayt "mos to'plam yo'q" deydi
Menyuda nechta taom? Bugun 40 ta, lekin tizim boshqa oshxonalarga ham sotiladi — 100 000 gacha
Narxlar qanday? Butun, musbat, so'mda

Oxirgi ikki savol eng muhimi. "40 ta taom" bo'lsa, istalgan yechim bir zumda ishlaydi. "100 000 ta" bo'lsa, O(n²) — 5 milliard juft. Hajm — algoritmni tanlashning asosiy omili.

3.2 Kirish va chiqish

Shartni funksiya imzosiga aylantiramiz: findPair(prices, target). Kirish — narxlar massivi va karta summasi. Chiqish — ikki indeks [i, j] (i < j) yoki null. Nega narxlar emas, indekslar? Bir xil narxli ikki taom bo'lsa, narx qaysi taomligini aytmaydi.

3.3 Misollar jadvali

Kod yozishdan oldin qo'lda misollar tuzamiz. Ular keyin testlarga aylanadi:

Kirish Kutilgan Nega
[35 000, 28 000, 30 000, 65 000, 5 000, 70 000], 100 000 [0, 3] yoki [2, 5] ikki juft bor
shu menyu, 1 000 null juft yo'q
[50 000], 100 000 null bitta taom — juft yo'q
[50 000, 50 000], 100 000 [0, 1] narx bir xil, taom har xil
[], 100 000 null bo'sh menyu

Birinchi qatorga qarang: ikki to'g'ri javob bor. Bu darhol bir xulosa beradi. Testda aniq juftni emas, juftning shartini tekshirish kerak: yig'indi kartaga teng va indekslar har xil.

Tekshirib ko'ring: Nega to'rtinchi misol ([50 000, 50 000]) alohida jadvalga kiritildi?

Javob

Chunki bu — tuzoq. Bitta taomni "o'zi bilan" juftlab qo'yadigan xato yechim [50 000], 100 000 uchun ham [0, 0] qaytaradi. To'rtinchi misol esa to'g'ri yechim bir xil narxli ikki xil taomni topishini tekshiradi. Ikkalasi birga "bitta taom ikki marta" xatosini ushlaydi.

4. M — tanish naqshga moslash

Endi o'zimizdan so'raymiz: "Bunga o'xshash masalani qayerda ko'rganman?" Shartdagi kalit so'zlar yordam beradi:

  • "ikki element, yig'indisi teng" — juftlar masalasi. Hamma juftlar — O(n²) sodda yechim.
  • "juftini tez topish" — Hash map bilan hisoblash naqshlari: ko'rilganini eslab qolish.
  • "agar narxlar saralangan bo'lsa" — Ikki ko'rsatkich: ikki chetdan bir-biriga yurish.

Bitta masalaga bir nechta naqsh to'g'ri kelishi normal. Keyingi qadamda ularni solishtiramiz. Kalit so'zlarni naqshga bog'lash — o'z alohida ko'nikmasi. Uni Naqshni tanish darsida to'liq jadval qilamiz.

5. P va I — reja va kod: avval brute force

5.1 Nega avval sodda yechim?

Eng ko'p xato — darhol eng "aqlli" yechimni yozishga urinish. Brute force uch sababga ko'ra birinchi:

  1. U to'g'ri. Mantiqi oddiy, xato qilish qiyin. Keyingi tez yechimlar shu bilan solishtiriladi.
  2. U tushunishni tekshiradi. Sodda yechimni ham yoza olmasangiz, masalani hali tushunmagansiz — U qadamiga qayting.
  3. U nimadir beradi. Intervyuda vaqt tugab qolsa ham, ishlaydigan yechim — "hech narsa yo'q" dan ancha yaxshi.

Reja oddiy so'zlar bilan: "Har taomni undan keyingi har taom bilan juftlab, yig'indini tekshiraman".

js
// 1-yechim: hamma juftlar
function findPairSlow(prices, target) {
  for (let i = 0; i < prices.length; i++) {
    for (let j = i + 1; j < prices.length; j++) {
      if (prices[i] + prices[j] === target) return [i, j];
    }
  }
  return null; // bunday juft yo'q
}

const menu = [35000, 28000, 30000, 65000, 5000, 70000];
console.log(findPairSlow(menu, 100000)); // [ 0, 3 ]
console.log(findPairSlow(menu, 33000)); // [ 1, 4 ]
console.log(findPairSlow(menu, 1000)); // null
console.log(findPairSlow([50000], 100000)); // null
console.log(findPairSlow([50000, 50000], 100000)); // [ 0, 1 ]

j = i + 1 dan boshlanadi — har juft bir marta ko'riladi va taom o'zi bilan juftlanmaydi. Misollar jadvalining hammasi o'tdi.

5.2 Brute force'ni baholash

Ikki ichma-ich sikl: n × (n − 1) ÷ 2 juft — O(n²) vaqt, O(1) qo'shimcha xotira. 40 taomda — 780 juft, bir zumda. 100 000 taomda — taxminan 5 milliard juft. Bu soniyalar emas, daqiqalar. Demak, E qadami "sekin" deydi va Match ga qaytamiz.

6. Optimallashtirish: ikki yo'l

6.1 Ortiqcha ish qayerda?

Optimallashtirishning birinchi savoli: "Brute force qaysi ishni qayta-qayta qilyapti?" Bu yerda har i uchun ichki sikl butun ro'yxatni qidiradi. Lekin aslida u bitta narsani qidiryapti: narxi aynan target - prices[i] bo'lgan taomni. "Shunday narx bormi?" savoliga Map O(1) da javob beradi.

6.2 Map bilan: "juftiga qancha kerak?"

Narxlarni chapdan o'ngga yuramiz. Har biri uchun "juftiga qancha kerak?" deb so'raymiz va javobni oldin ko'rilganlar orasidan qidiramiz. Topilmasa — joriy narxni Map'ga yozamiz:

js
// 2-yechim: ko'rilgan narxlarni Map'da eslab qolish
function findPair(prices, target) {
  const seen = new Map(); // narx → indeks
  for (let i = 0; i < prices.length; i++) {
    const need = target - prices[i]; // juftiga qancha kerak
    if (seen.has(need)) return [seen.get(need), i];
    seen.set(prices[i], i);
  }
  return null;
}

const menu = [35000, 28000, 30000, 65000, 5000, 70000];
console.log(findPair(menu, 100000)); // [ 0, 3 ]
console.log(findPair(menu, 33000)); // [ 1, 4 ]
console.log(findPair([50000, 50000], 100000)); // [ 0, 1 ]

Avval qidirib, keyin yozish tartibi muhim. Teskarisi bo'lsa, 50 000 so'mlik taom o'zini topib, [0, 0] qaytarardi. Bir xil narxli ikki taomda esa Map'da birinchisining indeksi turadi va ikkinchisi uni topadi — [0, 1].

Baho: bitta sikl, Map amallari O(1) — O(n) vaqt. Lekin Map n tagacha yozuv saqlaydi — O(n) xotira. Vaqt yutdik, xotira berdik.

6.3 Saralash va ikki ko'rsatkich

Ikkinchi yo'l. Narxlar saralangan bo'lsa, ikki chetdan yuramiz. Yig'indi kichik bo'lsa — chap ko'rsatkichni o'ngga (kattaroq narx). Katta bo'lsa — o'ngni chapga. Indekslarni yo'qotmaslik uchun saralashdan oldin har narxga asl indeksini biriktiramiz:

js
// 3-yechim: saralash + ikki ko'rsatkich
function findPairSorted(prices, target) {
  const order = prices.map((price, i) => [price, i]) // asl indeks
    .sort((a, b) => a[0] - b[0]);
  let left = 0;
  let right = order.length - 1;
  while (left < right) {
    const sum = order[left][0] + order[right][0];
    if (sum === target) {
      return [order[left][1], order[right][1]].sort((a, b) => a - b);
    }
    if (sum < target) left++; // yig'indi kichik — kattaroq kerak
    else right--; // katta — kichikroq kerak
  }
  return null;
}

const menu = [35000, 28000, 30000, 65000, 5000, 70000];
console.log(findPairSorted(menu, 100000)); // [ 2, 5 ]
console.log(findPairSorted(menu, 33000)); // [ 1, 4 ]
console.log(findPairSorted(menu, 1000)); // null

Birinchi chaqiruv [0, 3] emas, [2, 5] qaytardi: 30 000 + 70 000. Bu ham to'g'ri — U qadamidagi savol ("bir nechta juft bo'lsa?") aynan shu holat uchun edi.

Baho: saralash — O(n log n), ikki ko'rsatkich — O(n). Xotira — order massivi uchun O(n). Agar indekslar kerak bo'lmasa va asl massivni saralash mumkin bo'lsa (sort joyida), qo'shimcha xotira O(1) gacha tushadi. Narxlar bazadan allaqachon saralangan holda kelsa — vaqt O(n), xotira O(1).

6.4 E — baholash va o'lchov

Uchala yechimni eng yomon holatda (juft yo'q) benchmarking darsidagi usulda o'lchadik — har n alohida jarayonda, isitish, mediana; raqamlar taxminiy:

Taomlar (n) Hamma juftlar Map Saralash + ko'rsatkichlar
5 000 ≈ 10 ms ≈ 0,33 ms ≈ 1,2 ms
10 000 ≈ 42 ms (×4,0) ≈ 0,75 ms (×2,2) ≈ 2,7 ms (×2,2)
20 000 ≈ 167 ms (×4,0) ≈ 1,5 ms (×2,0) ≈ 5,4 ms (×2,0)
40 000 ≈ 670 ms (×4,0) ≈ 3,4 ms (×2,3) ≈ 12 ms (×2,2)
40 000 taom, juft yo'q: uch yechim
  • Hamma juftlar, O(n²)670 ms
  • Saralash, O(n log n)12 ms
  • Map, O(n)3,4 ms

Manba: O'lchov: 12/32 dagi usul (har n alohida jarayonda, isitish, mediana), Node 24.21, i5-12500H, Windows 11, 2026-10-06; isitish 3, 7 o'lchov; narxlar mulberry32 (urug' 57)

Big-O bashorati tasdiqlandi: n ikki baravar oshganda brute force to'rt baravar sekinlashdi, qolgan ikkitasi — ikki baravarga yaqin. Map saralashdan taxminan 3–4 baravar tez: unda saralash yo'q. Ikkalasi ham brute force'dan 50–200 baravar tez.

7. Vaqt va xotira: tanlov

Uchta yechim — uchta savdo. Bu Xotira murakkabligi darsidagi vaqt va xotira almashinuvi (time-space trade-off):

Yechim Vaqt Qo'shimcha xotira Qachon tanlanadi
Hamma juftlar O(n²) O(1) n kichik (yuzlab), kod soddaligi muhim
Map O(n) O(n) odatiy holat: tezlik muhim, xotira yetarli
Saralash + ko'rsatkichlar O(n log n) O(1) … O(n) xotira tor yoki ma'lumot allaqachon saralangan

"Eng yaxshi" yechim yo'q — vaziyatga eng mos yechim bor. «Bahor» saytida Map tanlanadi: menyu kichik, server xotirasi yetarli. Eski kassa apparatida esa, Xotira murakkabligi darsida ko'rganimizdek, xotira tor. U yerda saralash yaxshiroq bo'lishi mumkin.

Bu savdo butun kurs bo'ylab takrorlanadi: kesh (xotira evaziga tezlik), indeks (bazada joy evaziga tez qidiruv), memoization (DP jadvali). Har safar ikki savol bering: "Qancha vaqt yutaman?" va "Qancha xotira beraman?"

Tekshirib ko'ring: Narxlar ro'yxati bir marta yuklanadi va keyin kun bo'yi 10 000 ta har xil karta summasi uchun juft qidiriladi. Qaysi yondashuv yaxshiroq?

Javob

Narxlarni bir marta saralab qo'yish (O(n log n)) va har so'rovda faqat ikki ko'rsatkich (O(n)) ishlatish. Yoki narxlarni bir marta Map/Set ga yig'ib, har so'rovda bir o'tish. Asosiy fikr: takrorlanadigan ishni (saralash, Map yasash) so'rovlardan oldinga, bir martaga chiqarish. Har so'rovda qaytadan saralash — eng yomon tanlov: 10 000 × O(n log n).

8. R — qo'lda tekshirish

Kod yozildi — lekin hali tugamadi. Review qadami: kodni kompyutersiz, qog'ozda kichik misol bilan "ishga tushiring". Map yechimini [50 000, 50 000], 100 000 bilan:

  • i = 0: need = 50 000, Map bo'sh → topilmadi. Map: {50 000 → 0}.
  • i = 1: need = 50 000, Map'da bor → [0, 1].

Endi [50 000], 100 000: i = 0 — topilmadi, sikl tugadi → null.

Qo'lda kuzatish (Chegaraviy holatlar, brute force va invariant dagi trace jadvali) ikki narsani ushlaydi. Birinchisi — chegaraviy holatlardagi xatolar. Ikkinchisi — "kod men o'ylagandan boshqacha ishlayapti" holati. Keyin avtomatik testlar ishga tushadi: misollar jadvali va brute force bilan solishtirish. Ikkinchi usulni 3-mashqda yozasiz.

9. Qotib qolganda

Jarayon bo'lsa ham, ba'zan hech narsa xayolga kelmaydi. Shunda nima qilish kerak:

  1. Qaytib tushuning. Ko'pincha qotib qolish noaniq shartdan keladi. Misollar jadvaliga yana bitta qator qo'shing.
  2. Kichraytiring. 3 ta element bilan qo'lda yeching. Qo'lingiz nima qilayotganini kuzating — bu algoritm.
  3. Brute force'ni yozing. Hatto O(2ⁿ) bo'lsa ham. Uni yozish jarayonida ortiqcha ish ko'rinadi.
  4. Naqshlar ro'yxatidan o'ting. Saralash yordam beradimi? Hash map? Ikki ko'rsatkich? DP? Har biriga "bu yerda nima beradi?" deb savol bering.
  5. Vaqtni chegaralang. Mashqda 25–30 daqiqa natijasiz o'tsa — yechimni o'qing, tushuning va bir necha kundan keyin o'zingiz qayta yeching. Bu yengilish emas, o'rganishning bir usuli. Buni LeetCode uslubidagi muntazam mashq darsida rejaga aylantiramiz.

10. Ko'p uchraydigan xatolar

10.1 Darhol kod yozish

Masalani o'qib, birinchi qatordan kodga o'tish. Natija: yarim soatdan keyin boshqa masalani yechganingiz ma'lum bo'ladi. Tuzatish: kamida uchta misolni qo'lda yozmaguncha klaviaturaga tegmang.

10.2 Brute force'ni o'tkazib yuborish

"Bu juda sekin, yozishga arzimaydi" — lekin aynan u tez yechimni tekshiradi. Tuzatish: sodda yechimni test faylida saqlang. U kodda emas, testda yashaydi.

10.3 Bitta javobni kutish

Testda assert.deepEqual(findPair(menu, 100000), [0, 3]) yozsangiz, to'g'ri [2, 5] javobi "xato" deb chiqadi. Tuzatish: javobning shartini tekshiring (yig'indi, indekslar har xil), aniq qiymatini emas.

10.4 Hajmni so'ramaslik

O(n²) yechim 40 ta taomda a'lo, 100 000 tada esa yaroqsiz. Tuzatish: U qadamida doim "n qancha bo'lishi mumkin?" deb so'rang va javobni izohda yozing.

11. Mashqlar

1-mashq (oson): Sonlar bilan baholang

Menyuda 1 000 ta taom bor va juft yo'q (eng yomon holat). Brute force nechta juftni tekshiradi? Javob: [:499500]. Map yechimi nechta narxni Map'ga yozadi? Javob: [:1000].

Yechim

Hamma juftlar: 1 000 × 999 ÷ 2 = 499 500. Map yechimi har narxni bir marta ko'radi va (juft topilmagani uchun) har birini Map'ga yozadi — 1 000 ta yozuv. Mana savdo: yarim million tekshiruv o'rniga ming qadam, evaziga ming yozuvlik xotira.

2-mashq (o'rta): UMPIRE bilan yeching

Jasur aka har kungi tushumni ro'yxatda saqlaydi (million so'mda). U tushum ketma-ket o'sgan eng uzun davrni (kunlar sonini) bilmoqchi. Masalan, [4, 5, 7, 6, 8, 9, 11, 10] da 6, 8, 9, 11 — 4 kun. UMPIRE bilan yeching: (U) uchta savol va misollar jadvali, (M) naqsh, (P) brute force rejasi, (I) tez yechim longestGrowth(revenue), (E) Big-O. Ishora: har kun uchun "bugun tugaydigan o'sish davri qancha?" degan bitta son yetadi.

Yechim

U. Savollar: "Teng tushum o'sish hisoblanadimi?" (yo'q, qat'iy o'sish). "Bo'sh ro'yxatda nima?" (0). "Bitta kunda-chi?" (1). Misollar: [4, 5, 7, 6, 8, 9, 11, 10] → 4; [5, 5, 5] → 1; [] → 0.

M. "Ketma-ket", "eng uzun davr" — bitta o'tish bilan joriy uzunlikni yuritish. Bu suriluvchi oynaning sodda turi (Sliding window).

P. Brute force: har kundan boshlab, o'sish to'xtaguncha yurish — O(n²). Tez reja: chapdan o'ngga yurib, current ni yuritish. Bugun kechagidan katta bo'lsa — current + 1, aks holda 1.

js
function longestGrowth(revenue) {
  if (revenue.length === 0) return 0; // kun yo'q — davr yo'q
  let best = 1;
  let current = 1; // bugun tugaydigan o'sish davri
  for (let i = 1; i < revenue.length; i++) {
    current = revenue[i] > revenue[i - 1] ? current + 1 : 1;
    best = Math.max(best, current);
  }
  return best;
}

// tushum, million so'mda
console.log(longestGrowth([4, 5, 7, 6, 8, 9, 11, 10])); // 4
console.log(longestGrowth([5, 5, 5])); // 1
console.log(longestGrowth([])); // 0

R. [5, 5, 5]: i = 1 — 5 > 5 yolg'on, current = 1; i = 2 — xuddi shunday. best = 1 .

E. Bitta sikl — O(n) vaqt, O(1) xotira. Brute force O(n²) edi. Bu yerda tezlik uchun xotira berish shart emas — eng yaxshi holat.

3-mashq (qiyin): Tez yechimni brute force bilan himoyalang

kurs/mashqlar/14/56-jarayon/juft.test.mjs faylida findPairSlow va findPair ni yozing. Yana checkAnswer(prices, target, answer) funksiyasini yozing: u javobni brute force natijasi bilan shart bo'yicha solishtirsin. Juft yo'q bo'lsa — null kutiladi. Juft bor bo'lsa — yig'indi kartaga teng va indekslar har xil. Testlar: «Bahor» menyusi; chegaraviy holatlar (bo'sh, bitta taom, ikki bir xil narx); urug'li generator bilan 500 ta tasodifiy menyu.

Yechim
js
// kurs/mashqlar/14/56-jarayon/juft.test.mjs
import { test } from "node:test";
import assert from "node:assert/strict";

function findPairSlow(prices, target) {
  for (let i = 0; i < prices.length; i++) {
    for (let j = i + 1; j < prices.length; j++) {
      if (prices[i] + prices[j] === target) return [i, j];
    }
  }
  return null;
}

function findPair(prices, target) {
  const seen = new Map();
  for (let i = 0; i < prices.length; i++) {
    const need = target - prices[i];
    if (seen.has(need)) return [seen.get(need), i];
    seen.set(prices[i], i);
  }
  return null;
}

// Javob to'g'rimi? Juftning o'zini emas, shartini tekshiramiz
function checkAnswer(prices, target, answer) {
  const expected = findPairSlow(prices, target);
  if (expected === null) return answer === null;
  if (answer === null) return false;
  const [i, j] = answer;
  return i !== j && prices[i] + prices[j] === target;
}

function makeRandom(seed) {
  return () => (seed = (seed * 16807) % 2147483647);
}

test("«Bahor» menyusi: 100 000 so'mlik karta", () => {
  const menu = [35000, 28000, 30000, 65000, 5000, 70000];
  assert.ok(checkAnswer(menu, 100000, findPair(menu, 100000)));
});

test("chegaraviy: bo'sh, bitta taom, ikki bir xil narx", () => {
  assert.equal(findPair([], 100000), null);
  assert.equal(findPair([50000], 100000), null);
  assert.deepEqual(findPair([50000, 50000], 100000), [0, 1]);
});

test("500 ta tasodifiy menyu: Map = hamma juftlar", () => {
  const random = makeRandom(57);
  for (let k = 0; k < 500; k++) {
    const n = random() % 12;
    const prices = Array.from({ length: n },
      () => 5000 * (1 + random() % 10));
    const target = 5000 * (2 + random() % 18);
    const answer = findPair(prices, target);
    assert.ok(checkAnswer(prices, target, answer), `${prices}`);
  }
});

Papkada node --test ni ishga tushiring. Bizda (Node 24.21.0) shunday chiqdi — millisekundlar sizda boshqacha bo'ladi:

text
✔ «Bahor» menyusi: 100 000 so'mlik karta (0.7974ms)
✔ chegaraviy: bo'sh, bitta taom, ikki bir xil narx (0.7489ms)
✔ 500 ta tasodifiy menyu: Map = hamma juftlar (3.102ms)
ℹ tests 3
ℹ suites 0
ℹ pass 3
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 10.61

Tasodifiy narxlar 5 000 ning karralilari, faqat 10 xil — shuning uchun bir xil narxlar va bir nechta to'g'ri juft tez-tez uchraydi. Tuzoqlarni aynan shunday holatlar ochadi. assert.ok ning ikkinchi argumenti — test yiqilganda chiqadigan xabar. Unda yiqitgan menyu ko'rinadi va xatoni qayta yaratish oson bo'ladi.

4-mashq: Amaliy tajriba — yechim kundaligi

kurs/mashqlar/14/MURAKKABLIK.md ga uch qator qo'shing: sovg'a kartasi juftini topishning uch yechimi. "Qachon tanlanadi" degan ustun ham qo'shing. Keyin kurs/mashqlar/14/56-jarayon/README.md faylida bugungi masala uchun UMPIRE yozuvini qoldiring: har qadamga 1–3 qator.

Yechim
text
| Masala | Yechim | Vaqt | Xotira | Qachon |
|---|---|---|---|---|
| Karta jufti | hamma juftlar | O(n²) | O(1) | n kichik |
| Karta jufti | Map | O(n) | O(n) | odatiy |
| Karta jufti | saralash + 2 ko'rsatkich | O(n log n) | O(1)–O(n) | xotira tor |

README namunasi:

text
U: ikki XIL taom, yig'indi = karta; juft yo'q → null; n ≤ 100 000
M: juft + yig'indi → hash map; saralangan → ikki ko'rsatkich
P: avval hamma juftlar (test uchun), keyin Map
I: findPair — "juftiga qancha kerak?", avval qidir, keyin yoz
R: [50 000, 50 000] → [0, 1]; [50 000] → null
E: O(n) / O(n); 40 000 da ≈ 3,4 ms (brute force ≈ 670 ms)
bash
git add 14/MURAKKABLIK.md 14/56-jarayon
git commit -m "14/56: UMPIRE — sovg'a kartasi jufti, uch yechim va test"

12. Real ishda

  • Ish vazifalari. Jira yoki Trello'dagi vazifa ham noaniq bo'ladi. U qadamidagi savollar ("hajmi qancha?", "bo'sh bo'lsa nima?") — jamoada eng qadrlanadigan odatlardan biri. Ular keyingi qayta ishlashni tejaydi.
  • Kod ko'rib chiqish. "Bu yerda n qancha bo'lishi mumkin?" va "eng sodda yechim bilan solishtirganmisiz?" — tajribali dasturchilarning odatiy savollari.
  • Intervyu. Texnik intervyuda baholanadigan narsa — aynan shu jarayon. Savol berish, misol tuzish, avval brute force aytish, keyin optimallashtirish va murakkablikni tushuntirish. Ko'p kompaniyalar "to'g'ri javob, lekin jim yozilgan" yechimdan ko'ra "ovoz chiqarib fikrlangan, biroz kamchilikli" yechimni yuqoriroq baholaydi. Texnik intervyu bilan kursning yakuniy qismida alohida shug'ullanamiz.
  • Vaqt va xotira savdosi — kesh, indeks, CDN, memoization: arxitektura qarorlarining ko'pi aynan shu tanlov.

Xulosa

  • UMPIRE: tushun, moslashtir, reja, kod, qo'lda tekshir, baholash. Baholash "sekin" desa — Match ga qaytiladi.
  • U qadamida savollar va misollar jadvali: hajm, takrorlar, bo'sh kirish, bir nechta javob. Misollar keyin testga aylanadi.
  • Avval brute force: u to'g'ri, tushunishni tekshiradi va tez yechimning "hakami" bo'ladi.
  • Optimallashtirish savoli: "qaysi ish qayta-qayta qilinyapti?" Juft masalasida: O(n²) → Map bilan O(n) yoki saralash bilan O(n log n).
  • O'lchov tasdiqladi: 40 000 taomda 670 ms → 3,4 ms. Tezlik ko'pincha xotira evaziga keladi — tanlovni vaziyat hal qiladi.

Keyingi dars: Naqshni tanish — masala shartidagi kalit so'zlar ("saralangan", "qism-massiv", "barcha variant", "eng kam usul") qaysi texnikaga ishora qilishini jadval qilamiz.

Manbalar

  • George Pólya, "How to Solve It", Princeton University Press, 1945 (yangi nashrlari bor).
  • CodePath: "UMPIRE Interview Strategy" — guides.codepath.org
  • LeetCode masalasi (shartini o'zingiz o'qing): 1 "Two Sum", 167 "Two Sum II — Input Array Is Sorted".
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Masala yechish jarayoni: UMPIRE, avval brute force, keyin optimallashtirish — IlmHamroh