四月的第一天
阳光洒出来了
在家什么都好
就是太安逸静谧了
太不真实了
题目描述:
给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数。
示例 1 :
输入:nums = [1,1,1], k = 2
输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。
说明 :
数组的长度为 [1, 20,000]。
数组中元素的范围是 [-1000, 1000] ,且整数 k 的范围是 [-1e7, 1e7]。
思路解析:
这一题我刚开始本来想用双指针的方法来做,就是先固定start指针在0下标的位置上,然后向右移动end指针。如果sum(nums[start:end+1])子序列的和大于k,则将start指针右移,反之右移end指针,直至遍历结束。后来发现这里面有个最大的bug就是,如果k为负数的话,则以上情况均不成立了,或者说是相反了。情况比较复杂,所以就舍弃了这种想法。
后面,又想到了直接的暴力法。就是两次遍历嘛,固定一个start指针嘛,然后不停的右移end指针,查找是否连续子序列之和为k,思路很简单。
代码如下:
class Solution(object):
def subarraySum(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
same_length = 0
for start in range(len(nums)):
sums = 0
for end in range(start, len(nums)):
sums += nums[end]
if sums == k:
same_length += 1
return same_length
if __name__ == "__main__":
nums = [-1,-1,1]
k = 0
length = Solution().subarraySum(nums, k)
print(length)
暴力法又是超出时间限制了,害。
后面看到了网上比较流行的字典去重法,刚开始没看懂,因为只有一次遍历,我觉得中间的子序列之和好像没有计算。好好想了一下才发觉这个方法的巧妙,因为题目给定了是连续的子序列,所以如果存在这样的子序列之和为k的话,那么sum-k的值一定是等于以下标为0开始的子序列之和。那么我们只要用字典来记录sum和的值即可,相同的值出现,把字典对应key的value值加1.
代码如下:
class Solution(object):
def subarraySum(self, nums, k):
"""
字典法记录重复值
:type nums: List[int]
:type k: int
:rtype: int
"""
same_length = 0
num_sum = 0
nums_dict = {0:1}
for val in nums:
num_sum += val
same_length += nums_dict.get(num_sum-k, 0)
if num_sum in nums_dict:
nums_dict[num_sum] += 1
else:
nums_dict[num_sum] = 1
return same_length
if __name__ == "__main__":
nums = [-1,-1,1]
k = 0
length = Solution().subarraySum(nums, k)
print(length)
执行效率在80%左右,还算可以!