動機

我忘了prefix sum!! 同時,這題不能用sliding window

Problem

Given an array of integers nums and an integer k, return the total number of continuous subarrays whose sum equals to k.

 

Example 1:

Input: nums = [1,1,1], k = 2Output: 2

Example 2:

Input: nums = [1,2,3], k = 3Output: 2

 

Constraints:

  • 1 <= nums.length <= 2 * 104
  • -1000 <= nums[i] <= 1000
  • -107 <= k <= 107

Sol

這題不能用sliding window,因為array中有負數,不會越加越多

這樣不能調左邊的index讓window的總和縮小

所以可以用prefix sum來算區間和,之後再找對應的和

class Solution:
    def subarraySum(self, nums: List[int], k: int) -> int:
        # 忘了可以用presum
        
        sums, cnt, ret = [{}, 0, 0]
        for i in range(len(nums)):
            cnt += nums[i]
            if cnt not in sums:
                sums[cnt] = [i]
            else:
                sums[cnt].append(i)
        #print(sums)
        for left in sums.keys():
            # k ==  sums[j] - sums[i]
            right = k + left
            if left == k: # 可以用在sums放來省略這一段
                ret += len(sums[left])
            if right in sums:
                for i in sums[left]:
                    tmp = sums[right]
                    ret += len(tmp)-bisect_left(tmp,i+1)
        return ret

原本是

a[a]+...+a[b] = k

變成

sum[b]-sum[a-1] = k
=>
sum[b]-k = sum[a-1]

是不是只要是連續區間和就可以用這種手段

class Solution:
    def subarraySum(self, nums: List[int], k: int) -> int:
        ret = 0
        tbl = {0:1} # sum[i] is equal to k!!
        cnt = 0
        # sum(nums[j:i]) = sums[:i] - sum[:j] - 
        for n in nums:
            cnt += n
            if cnt-k in tbl:
                ret += tbl[cnt-k]
            tbl[cnt] = tbl.get(cnt,0)+1
        return ret

sum[i:j] = sum[:j]-sum[:i] 上面會用bisect_left,是因為要找比當前位置大的index,也就是找j,但其實可以改找i

class Solution:
    def subarraySum(self, nums: List[int], k: int) -> int:
        ret, cnt, tbl = [0, 0 , {0:1}]
        # sum(nums[j:i]) = sums[:i] - sum[:j]
        for n in nums:
            cnt += n
            ret += tbl.get(cnt-k,0)
            tbl[cnt] = tbl.get(cnt,0)+1
        return ret