Specimen 05 ยท O(n) amortized

Sliding Window

Instead of recomputing a sum for every possible window, keep a running total: drop the value that just left the frame, add the value that just entered. One frame, sliding โ€” not thousands of frames, recomputed.

โ† Back to the Field Guide
05-namuna ยท O(n) amortized

Sliding Window

Har bir mumkin bo'lgan window uchun sum'ni qaytadan hisoblash o'rniga, running total saqlang: freymdan chiqqan qiymatni ayiring, kirgan qiymatni qo'shing. Bitta freym siljiydi โ€” minglab freym qayta hisoblanmaydi.

โ† Qo'llanmaga qaytish

Intuition

Watch the bars below: the dashed box is the current window sliding one step at a time โ€” only the two edge values change each step, and the gold bars mark the best window found so far.

Tushuncha (Intuition)

Quyidagi ustunlarga qarang: shtrixli quti โ€” bir qadamda bir marta siljiydigan joriy window โ€” har qadamda faqat ikkita chekka qiymat o'zgaradi, oltin ustunlar esa hozirgacha topilgan eng yaxshi window'ni belgilaydi.

How It Works

  1. Fix the window size k (given by the problem) and check that the array has at least k elements โ€” with fewer than k elements, no window of that size exists.
  2. Build the first window by summing its k elements directly: window_sum = sum(arr[0:k]). This one-time cost covers indices 0 through k - 1.
  3. Record whatever the first window tells you โ€” e.g. set best = window_sum, since it's the only window seen so far.
  4. Slide the window one index at a time: for each next right edge i from k to len(arr) - 1, update the running total by subtracting the element leaving on the left, arr[i - k], and adding the element entering on the right, arr[i].
  5. After each slide, the running total is exactly the sum of the current window [i - k + 1, i] โ€” no re-summing needed โ€” so compare it against best and update if it's better.
  6. Repeat steps 4โ€“5 until i reaches the last index of the array; at that point every window of size k has been visited exactly once.
  7. Return whatever the problem asks for, derived from best โ€” a sum, a max, or (as in LC 643) an average obtained by dividing best by k.

Qanday Ishlaydi

  1. Window o'lchami kni belgilang (masala bergan) va array'da kamida k ta element borligini tekshiring โ€” k tadan kam element bo'lsa, shunday o'lchamdagi window umuman mavjud emas.
  2. Birinchi window'ni uning k ta elementini to'g'ridan-to'g'ri qo'shib quring: window_sum = sum(arr[0:k]). Bu bir martalik xarajat 0 dan k - 1 gacha bo'lgan indekslarni qamrab oladi.
  3. Birinchi window sizga nima aytayotganini qayd eting โ€” masalan, best = window_sum deb belgilang, chunki bu hozircha ko'rilgan yagona window.
  4. Window'ni bir indeksdan siljiting: har bir keyingi o'ng chet i uchun (k dan len(arr) - 1 gacha), chapdan chiqib ketayotgan elementni, arr[i - k]ni, ayirib va o'ngdan kirib kelayotgan elementni, arr[i]ni, qo'shib running total'ni yangilang.
  5. Har bir siljishdan so'ng, running total aynan joriy window [i - k + 1, i]ning yig'indisiga teng โ€” qayta qo'shish shart emas โ€” shuning uchun uni best bilan solishtiring va yaxshiroq bo'lsa yangilang.
  6. i array'ning oxirgi indeksiga yetguncha 4โ€“5-qadamlarni takrorlang; shu nuqtada har bir k o'lchamdagi window aynan bir marta ko'rib chiqilgan bo'ladi.
  7. Masala talab qilgan narsani, bestdan kelib chiqib qaytaring โ€” yig'indi, maksimum, yoki (LC 643'dagidek) bestni kga bo'lish orqali olingan average.

Complexity

Time: O(n). Building the very first window costs O(k) โ€” summing k elements once. After that, each of the remaining n - k slides does a fixed amount of work: one subtraction and one addition, regardless of how big k is. So the total work is O(k) + O(n - k) ยท O(1), which simplifies to O(n). Compare that to the brute-force approach of re-summing every window from scratch, which redoes O(k) work for each of the n - k + 1 windows โ€” O(nยทk) overall; sliding window collapses that k factor away entirely.

Space: O(1). The algorithm only ever tracks a running total and a best-so-far value (plus a loop index) โ€” no matter how long the array is or how big k is, no extra array, hash map, or other structure that grows with the input is ever allocated.

Murakkablik

Vaqt: O(n). Eng birinchi window'ni qurish O(k) turadi โ€” k ta elementni bir marta qo'shish. Shundan keyin, qolgan n - k ta siljishning har biri belgilangan miqdordagi ish qiladi: bitta ayirish va bitta qo'shish, k qanchalik katta bo'lishidan qat'i nazar. Shunday qilib, jami ish O(k) + O(n - k) ยท O(1) bo'lib, bu O(n)ga soddalashadi. Buni har bir window'ni noldan qayta qo'shadigan brute-force yondashuv bilan solishtiring โ€” u n - k + 1 ta window'ning har biri uchun O(k) ish takrorlaydi, jami O(nยทk); sliding window esa bu k ko'paytuvchisini butunlay yo'q qiladi.

Xotira: O(1). Algoritm faqat running total va best-so-far qiymatini (va loop indeksini) kuzatib boradi โ€” array qanchalik uzun yoki k qanchalik katta bo'lishidan qat'i nazar, kirish hajmiga qarab o'sadigan qo'shimcha array, hash map yoki boshqa struktura hech qachon yaratilmaydi.

Common Mistakes

  • Recomputing the window sum from scratch on every slide (e.g. sum(arr[i-k+1:i+1]) inside the loop) instead of updating the running total. Fix: only ever add the one incoming value and subtract the one outgoing value โ€” re-summing the whole window throws away the entire point of the technique and silently turns O(n) back into O(nยทk).
  • Off-by-one on which index leaves the window. When the window's right edge is at i, the element leaving is arr[i - k] (the previous left edge), not arr[i - k + 1] or arr[i - 1]. Fix: write out a tiny example by hand (say k = 3, i = 5) and check the index arithmetic before trusting it in code.
  • Forgetting to guard against an array shorter than k, which leaves no valid window at all. Fix: check len(arr) >= k before building the first window, and decide up front what the function should return when it isn't (often 0, None, or an explicit error, depending on the problem).
  • Returning the raw window sum when the problem asks for an average (like LC 643) or some other derived value. Fix: keep the running total as the sum throughout the scan โ€” dividing every step is wasteful and can introduce floating-point drift โ€” and convert to the final answer once, after the best sum has been found.

Ko'p Uchraydigan Xatolar

  • Har bir siljishda window sum'ini noldan qayta hisoblash (masalan, loop ichida sum(arr[i-k+1:i+1])) โ€” running total'ni yangilash o'rniga. Yechim: har doim faqat bitta kirib kelayotgan qiymatni qo'shing va bitta chiqib ketayotgan qiymatni ayiring โ€” butun window'ni qayta qo'shish texnikaning butun mag'zini yo'qqa chiqaradi va O(n)ni sezilmagan holda yana O(nยทk)ga aylantiradi.
  • Qaysi indeks window'dan chiqishida off-by-one xatosi. Window'ning o'ng cheti ida bo'lsa, chiqib ketayotgan element arr[i - k] (avvalgi chap chet), arr[i - k + 1] yoki arr[i - 1] emas. Yechim: qo'lda kichik misol yozing (aytaylik, k = 3, i = 5) va kodga ishonishdan oldin indeks arifmetikasini tekshiring.
  • Array'ning kdan qisqa bo'lishiga qarshi tekshiruvni unutish โ€” bu holda hech qanday to'g'ri window mavjud emas. Yechim: birinchi window'ni qurishdan oldin len(arr) >= k ekanligini tekshiring va bu bo'lmasa funksiya nima qaytarishi kerakligini oldindan hal qiling (odatda 0, None, yoki masalaga qarab aniq xato).
  • Masala average so'ragan (LC 643'dagidek) yoki boshqa hosila qiymat kerak bo'lganda xom window sum'ini qaytarish. Yechim: skanerlash davomida running total'ni yig'indi sifatida saqlang โ€” har bir qadamda bo'lish behuda va floating-point siljishga olib kelishi mumkin โ€” va yakuniy javobga faqat eng yaxshi yig'indi topilgach, bir marta o'ting.

When to Use It

  • The problem asks for an aggregate โ€” sum, average, max, min, or count of matches โ€” over every contiguous subarray or substring of a fixed length k. That's the direct fit for the fixed-size sliding window covered here.
  • You'd otherwise recompute that aggregate from scratch for every window โ€” O(nยทk) โ€” and want to bring it down to O(n) by updating incrementally as the window slides one step at a time.
  • Look for phrasing like "of size k", "k consecutive elements", or "window of length k" in the problem statement โ€” that's usually a direct signal.
  • If the window's size itself needs to grow or shrink depending on a condition (e.g. "longest substring without repeating characters", "smallest subarray with sum โ‰ฅ target"), that's the variable-size sliding window cousin โ€” same subtract/add spirit, but with two independently moving edges instead of one block sliding by exactly one step.

Qachon Ishlatish Kerak

  • Masala belgilangan k uzunlikdagi har bir ketma-ket subarray yoki substring bo'yicha agregat โ€” yig'indi, average, maksimum, minimum yoki mos kelishlar soni โ€” so'raydi. Bu shu yerda ko'rib chiqilgan belgilangan o'lchamli sliding window uchun to'g'ridan-to'g'ri mos keladi.
  • Aks holda siz o'sha agregatni har bir window uchun noldan qayta hisoblardingiz โ€” O(nยทk) โ€” va window bir qadamdan siljiganda uni bosqichma-bosqich yangilab, buni O(n)ga tushirmoqchisiz.
  • Masala matnida "of size k", "k consecutive elements" yoki "window of length k" kabi iboralarni izlang โ€” bu odatda to'g'ridan-to'g'ri signal.
  • Agar window'ning o'lchami shartga qarab o'sishi yoki qisqarishi kerak bo'lsa (masalan, "longest substring without repeating characters", "smallest subarray with sum โ‰ฅ target"), bu variable-size sliding window'ning qarindoshi โ€” xuddi shu ayirish/qo'shish ruhi, lekin bitta blok bir qadamga siljish o'rniga ikkita mustaqil harakatlanadigan chet bilan.

LeetCode Practice

643. Maximum Average Subarray I โ†—

Restated: given an integer array nums of length n and an integer k, find the contiguous subarray of length exactly k that has the maximum average value, and return that average. Any answer within 10โปโต of the true value is accepted.

  1. Spot the shape. Fixed window size k, and you need the best average over every length-k subarray โ€” that's the fixed-size sliding window pattern, not a brute-force scan of every possible window.
  2. Simplify the goal. Maximizing average (sum / k) over windows of the same fixed size k is the same as maximizing the plain sum, since dividing by the same constant k never changes which window wins. So track the maximum sum, and only divide by k once, at the very end.
  3. Build the first window. window_sum = sum(nums[:k]) covers indices 0 through k - 1; set max_sum = window_sum as the best seen so far.
  4. Slide across the rest of the array. For each i from k to len(nums) - 1, update window_sum += nums[i] - nums[i - k] (add the entering value, drop the leaving one), and update max_sum if window_sum is bigger.
  5. Convert once at the end. Return max_sum / k โ€” the required average of the best window found.
def findMaxAverage(nums, k):
    # build the first window: sum of the first k elements (indices 0..k-1)
    window_sum = sum(nums[:k])
    max_sum = window_sum

    # slide the window one index at a time across the rest of the array
    for i in range(k, len(nums)):
        window_sum += nums[i] - nums[i - k]  # add the value entering, drop the value leaving
        max_sum = max(max_sum, window_sum)

    return max_sum / k  # convert the best sum into an average, once, at the end

LeetCode Amaliyoti

643. Maximum Average Subarray I โ†—

Qayta bayon: uzunligi n bo'lgan butun sonlar array'i nums va butun son k berilgan โ€” average qiymati eng katta bo'lgan, uzunligi aynan k ga teng contiguous subarray'ni toping va o'sha average'ni qaytaring. Haqiqiy qiymatdan 10โปโต farq bilan berilgan har qanday javob qabul qilinadi.

  1. Shaklni tanib oling. Belgilangan window o'lchami k, va sizga har bir uzunligi k bo'lgan subarray ustidan eng yaxshi average kerak โ€” bu belgilangan o'lchamli sliding window pattern, har bir mumkin bo'lgan window'ni brute-force skanerlash emas.
  2. Maqsadni soddalashtiring. Bir xil belgilangan k o'lchamidagi window'lar ustida average'ni (sum / k) maksimallashtirish oddiy yig'indini maksimallashtirish bilan bir xil, chunki bir xil o'zgarmas kga bo'lish qaysi window g'olib chiqishini hech qachon o'zgartirmaydi. Shuning uchun maksimal yig'indini kuzating va faqat oxirida, bir marta, kga bo'ling.
  3. Birinchi window'ni quring. window_sum = sum(nums[:k]) 0 dan k - 1 gacha bo'lgan indekslarni qamraydi; hozircha ko'rilgan eng yaxshi natija sifatida max_sum = window_sum deb belgilang.
  4. Array'ning qolgan qismi bo'ylab siljiting. Har bir i uchun (k dan len(nums) - 1 gacha), window_sum += nums[i] - nums[i - k] ni yangilang (kirib kelayotgan qiymatni qo'shing, chiqib ketayotganini tashlang), va window_sum kattaroq bo'lsa max_sumni yangilang.
  5. Oxirida bir marta o'tkazing. max_sum / k ni qaytaring โ€” topilgan eng yaxshi window'ning talab qilingan average'i.
def findMaxAverage(nums, k):
    # build the first window: sum of the first k elements (indices 0..k-1)
    window_sum = sum(nums[:k])
    max_sum = window_sum

    # slide the window one index at a time across the rest of the array
    for i in range(k, len(nums)):
        window_sum += nums[i] - nums[i - k]  # add the value entering, drop the value leaving
        max_sum = max(max_sum, window_sum)

    return max_sum / k  # convert the best sum into an average, once, at the end

Check Yourself

O'zingizni Sinang

ยฉ 2026 Davronbek