Keep one running total while scanning the array once. At each position, ask a hash map: "have I seen running total minus k before?" Every yes marks a subarray that sums to exactly k โ found in O(1) per position instead of rechecking the whole history so far.
โ Back to the Field GuideArray bir marta skanerlanayotganda bitta running total saqlanadi. Har bir pozitsiyada hash map'ga savol beriladi: "running total minus k'ni avval ko'rganmidim?" Har bir "ha" javobi โ aynan k'ga teng bo'lgan subarray, va bu javob butun tarixni qayta qidirish o'rniga bitta O(1) lookup orqali topiladi.
โ Qo'llanmaga qaytishWatch the bars below: as the scan moves right, every matching stretch that sums to the target gets boxed โ no re-measuring, just one lookup per step against everything already seen.
Quyidagi ustunlarga qarang: skan o'ngga siljigan sari, target'ga teng bo'lgan har bir mos qism ramkaga olinadi โ qayta o'lchash yo'q, har qadamda hozirgacha ko'rilganlar orasida bitta lookup, xolos.
count = 0 (subarrays found so far) and total = 0 (the running prefix sum).seen = {0: 1}. This records that a prefix sum of 0 โ the "empty" total before any elements have been added โ has already occurred once.total, so total always holds the prefix sum through the current index.need = total - k โ the exact prefix sum an earlier position would need to have had for everything between that position and here to sum to k.need in seen. If it's there, add its count to count โ each occurrence marks a different earlier position where a matching subarray begins.seen[total] = seen.get(total, 0) + 1. Doing this after the lookup โ not before โ keeps the current position from ever matching against itself.count holds the total number of subarrays that sum to exactly k.count = 0 (hozirgacha topilgan subarray'lar soni) va total = 0 (running prefix sum) bilan boshlang.seen = {0: 1}. Bu hech qanday element qo'shilmagan holatdagi "bo'sh" prefix sum โ 0 โ allaqachon bir marta uchraganini bildiradi.totalga qo'shing, shunda total doimo hozirgi indeksgacha bo'lgan prefix sum'ni saqlaydi.need = total - kni hisoblang โ bu, agar oldingi biror pozitsiya shu qiymatga ega bo'lganida, o'sha pozitsiya bilan hozirgi orasidagi hamma narsa aynan k'ga teng bo'lishi uchun kerak bo'lgan prefix sum.needni seendan qidiring. Agar u u yerda bo'lsa, uning count'ini countga qo'shing โ har bir uchrash mos keluvchi subarray boshlanadigan boshqa-boshqa oldingi pozitsiyani bildiradi.seen[total] = seen.get(total, 0) + 1. Buni qidiruvdan keyin โ oldin emas โ bajarish hozirgi pozitsiyaning o'z-o'ziga mos kelib qolishining oldini oladi.count aynan k'ga teng bo'lgan subarray'larning jami sonini saqlaydi.Time: O(n). The array is scanned once, and each iteration does a constant amount of work โ one addition, one subtraction, and two hash map operations (a lookup and an insert/update), both O(1) on average for a Python dict. There's no nested loop re-scanning earlier positions, so the total work scales linearly with the length of the array.
Space: O(n). The hash map can end up holding one entry per distinct prefix sum encountered. In the worst case โ for example, when every prefix sum along the way is different, which happens whenever the array is all positive numbers โ that's up to n+1 entries (n array positions plus the seeded 0), so memory use grows linearly with the size of the input.
Vaqt: O(n). Array bir marta skanerlanadi, va har bir iteratsiya doimiy miqdordagi ish bajaradi โ bitta qo'shish, bitta ayirish, va ikkita hash map amali (bitta lookup va bitta insert/update), Python dict uchun ikkalasi ham o'rtacha O(1). Oldingi pozitsiyalarni qayta skanerlaydigan nested loop yo'q, shuning uchun jami ish array uzunligiga chiziqli proportsional bo'ladi.
Xotira: O(n). Hash map, uchragan har bir alohida prefix sum uchun bitta yozuv saqlashi mumkin. Eng yomon holatda โ masalan, yo'l davomidagi barcha prefix sum'lar har xil bo'lsa, bu array to'liq musbat sonlardan iborat bo'lganda sodir bo'ladi โ bu n+1 tagacha yozuv bo'lishi mumkin (n ta array pozitsiyasi va urug'langan 0), shuning uchun xotira sarfi kirish o'lchamiga chiziqli proportsional o'sadi.
{0: 1}. Starting seen empty misses every subarray that begins at index 0, because there's no earlier "0" prefix recorded for total - k to match against when the subarray's true starting point is the very beginning of the array. Fix: always initialize seen = {0: 1} before the loop.need first, then insert the current total โ otherwise, whenever k == 0, the current position's freshly-inserted total is already in seen by the time it checks itself, so the position matches against itself and reports a subarray that doesn't actually exist (e.g. nums = [1], k = 0 would wrongly report one match).Counter / defaultdict(int)), not a set โ with negative numbers in the array, the exact same prefix sum can legitimately occur at several different earlier positions, and each occurrence is a separate valid subarray; a set would only remember that the value was seen, not how many times.need backwards, e.g. k - total instead of total - k. Fix: the earlier prefix sum you're hunting for is total - k, because you want total - earlier == k, which rearranges to earlier == total - k โ not the other way around; swapping the subtraction silently returns wrong counts instead of raising any error.{0: 1} bilan urug'lantirishni unutish. seenni bo'sh boshlash index 0'dan boshlanadigan har qanday subarray'ni o'tkazib yuboradi, chunki subarray'ning haqiqiy boshlanish nuqtasi array boshi bo'lganda, total - k mos kelishi uchun oldindan yozilgan "0" prefix mavjud emas. Yechim: loop'dan oldin har doim seen = {0: 1} bilan boshlang.needni qidiring, keyin hozirgi totalni qo'shing โ aks holda, k == 0 bo'lganda, hozirgi pozitsiyaning yangi yozilgan totali u o'zini tekshirganida allaqachon seenda bo'ladi, shuning uchun pozitsiya o'z-o'ziga mos kelib, aslida mavjud bo'lmagan subarray'ni xabar qiladi (masalan, nums = [1], k = 0 uchun noto'g'ri bitta moslik topiladi).Counter / defaultdict(int)) foydalaning โ array'da manfiy sonlar bo'lsa, aynan bir xil prefix sum bir necha xil oldingi pozitsiyada qonuniy ravishda uchrashi mumkin, va har bir uchrash alohida haqiqiy subarray; set esa faqat qiymat ko'rilganini eslaydi, necha marta ko'rilganini emas.needni teskari hisoblash, masalan total - k o'rniga k - total. Yechim: siz qidirayotgan oldingi prefix sum โ total - k, chunki sizga total - earlier == k kerak, bu esa earlier == total - kga aylanadi โ aksincha emas; ayirishni almashtirish hech qanday xato chiqarmasdan, shunchaki noto'g'ri sonlarni qaytaradi.560. Subarray Sum Equals K โ
Restated: given an integer array nums and an integer k, return the number of contiguous subarrays whose elements sum to exactly k.
prefix[i] as the sum of nums[0..i-1]. Any subarray nums[i..j-1] then has sum prefix[j] - prefix[i] โ one subtraction instead of re-summing.j, the number of valid starting points is the number of earlier indices i where prefix[i] == prefix[j] - k. Checking every i for every j is still O(nยฒ); storing counts of prefix values seen so far in a hash map turns that inner search into an O(1) lookup.total replaces prefix[], updated as the array is scanned.{0: 1} before scanning, so subarrays starting at index 0 are counted correctly, and update the map only after the lookup at each step, so a subarray never matches itself.def subarraySum(nums, k):
# count: number of subarrays found so far that sum to exactly k
# total: running prefix sum -- sum of nums[0..i] at the current index i
count, total = 0, 0
# seen maps a prefix-sum value to how many earlier indices produced it
# seed with {0: 1}: the "empty" prefix (before index 0) sums to 0,
# so subarrays starting at index 0 can be counted too
seen = {0: 1}
for num in nums:
total += num
# an earlier prefix sum equal to (total - k) means everything
# between that earlier position and here sums to exactly k
need = total - k
count += seen.get(need, 0)
# record the current total only AFTER the lookup above, so this
# position never counts itself as a match when k == 0
seen[total] = seen.get(total, 0) + 1
return count
560. Subarray Sum Equals K โ
Qayta bayon: butun sonlardan iborat nums array va butun son k berilgan โ elementlari yig'indisi aynan kga teng bo'lgan contiguous subarray'lar sonini qaytaring.
prefix[i]ni nums[0..i-1]ning yig'indisi deb belgilang. Har qanday subarray nums[i..j-1]ning yig'indisi endi bitta ayirish bo'ladi: prefix[j] - prefix[i].j uchun, to'g'ri boshlanish nuqtalari soni โ prefix[i] == prefix[j] - k bo'lgan oldingi i indekslarining soni. Har bir j uchun har bir ini tekshirish hali ham O(nยฒ); hozirgacha ko'rilgan prefix qiymatlarning count'ini hash map'da saqlash bu ichki qidiruvni O(1) lookup'ga aylantiradi.prefix[] o'rniga bitta total o'zgaruvchisi ishlatiladi, array skanerlanayotganda yangilanib boradi.{0: 1} bilan urug'lantiring, shunda index 0'dan boshlanadigan subarray'lar to'g'ri sanaladi, va map'ni har bir qadamda faqat lookup'dan keyin yangilang, shunda subarray hech qachon o'z-o'ziga mos kelmaydi.def subarraySum(nums, k):
# count: number of subarrays found so far that sum to exactly k
# total: running prefix sum -- sum of nums[0..i] at the current index i
count, total = 0, 0
# seen maps a prefix-sum value to how many earlier indices produced it
# seed with {0: 1}: the "empty" prefix (before index 0) sums to 0,
# so subarrays starting at index 0 can be counted too
seen = {0: 1}
for num in nums:
total += num
# an earlier prefix sum equal to (total - k) means everything
# between that earlier position and here sums to exactly k
need = total - k
count += seen.get(need, 0)
# record the current total only AFTER the lookup above, so this
# position never counts itself as a match when k == 0
seen[total] = seen.get(total, 0) + 1
return count
nums[i..j-1] โ the subarray that starts at index i and ends right before j. prefix[j] is the sum of everything from the start through index j-1, and prefix[i] is the sum of everything from the start through index i-1; subtracting removes exactly the first i elements, leaving the subarray from i up to (but not including) j.need = total โ k = 0 to already be recorded as having occurred once. Seeding {0: 1} plants that virtual "occurred before any real element" entry, so subarrays starting right at the beginning of the array get counted just like any other.nums[i..j-1]ning yig'indisi โ i indeksidan boshlanib, j'dan darhol oldin tugaydigan subarray. prefix[j] โ boshidan (j-1)-indeksgacha bo'lgan hamma narsaning yig'indisi, prefix[i] esa boshidan (i-1)-indeksgacha bo'lgan hamma narsaning yig'indisi; ayirish aynan birinchi i ta elementni olib tashlaydi, va i'dan boshlanib j'gacha (j'ni o'z ichiga olmagan holda) davom etadigan subarray qoladi.need = total โ k = 0 ning avval bir marta uchragani deb qayd etilgan bo'lishini talab qiladi. {0: 1} bilan urug'lantirish aynan shu virtual "har qanday haqiqiy elementdan oldin uchragan" yozuvni o'rnatadi, shunda array boshida boshlanadigan subarray'lar ham boshqalari kabi sanaladi.