Leetcode 560. 和为k的子数组
暴力解法:
这道题的暴力解法非常通俗易懂,我们既然要找和为k的子数组的个数,那么我们只需要检查一遍所有的子数组就好了,所以两层循环然后时间复杂度是O(n^2)
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
res = 0
for i in range(len(nums)):
cur_sum = 0
for j in range(i, len(nums)):
cur_sum = cur_sum + nums[j]
if cur_sum == k:
res = res + 1
return res
哈希表前缀和解法:
这里如果想要把时间复杂度降低到O(n)的话我们需要只遍历数组一遍,怎么去实现呢,就是用哈希表来记录一些有用的信息,然后来避免用循环浪费时间去找我们已经可以获取的信息,在这里就是我们在记录从第一个子数组然后慢慢扩大到整个数组的过程中,记录下来他们的和,每一次我们扩展到新的长度时,我们check当前这个数组和target的差距是否在之前的连续数组中的和相等,如果相等的话证明我们可以得到count个数的子数组能够帮助我们去得target
就像这个图中举的例子,当我们遍历到[1, -1, 1, 1, 1] 的时候,我们的sum就是k,这时候需要的之前数组能给我们的值就是3-3 = 0,我们在哈希表中发现符合这个条件的子数组有两个,证明当前数组 - 这两个子数组其中任意一个 = 一个符合题目条件的子数组,这里就是 [1, -1, 1, 1, 1] 和 [1, 1, 1] 这里的第一个数组就是我们这个方法的一个edge case,在哈希表创建的时候,我们就应该在prefix 0 里面的count = 1,我们遍历结束的时候,刚好整个数组的和就是k,也就是我们要找prefix = 0 的count是多少,我们这时候需要他是1
接下来我们遍历到 loop 6 的时候,我们需要的是能够提供prefix是1 的子数组来使当前数组 - prefix是1的数组 = 符合条件的数组,也就是 [1, -1, 1, 1, 1, 1] 和 [1, 1, 1] 注意这里的111的下标是3, 4, 5 和上一个循环的不一样
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
# create the hash table and sum variable and result
prefix_count = {0: 1}
prefix_sum = 0
res = 0
# loop through the list to increase the current sublist until full
for num in nums:
prefix_sum = prefix_sum + num
# calculate the diff as the num that the prefix sum need to reach k
need = prefix_sum - k
# see if we do have the need in the prefix_sum hash table from previous sublist
# we visited, if so add its count to res and we add this prefix_sum's count
if need in prefix_count.keys():
res = res + prefix_count[need]
prefix_count[prefix_sum] = prefix_count.get(prefix_sum, 0) + 1
return res