题目描述
https://leetcode-cn.com/problems/maximum-size-subarray-sum-equals-k/
思路题解
滑动窗口+剪枝(时间超限)
因为本题目有负数,所以对于负数比较多而k为正数的情况,会时间超限。
class Solution:
def maxSubArrayLen(self, nums: List[int], k: int) -> int:
n=len(nums)
preSum=[0]*n
ans=0
for i in range(n):
preSum[i]=preSum[i-1]+nums[i]
if preSum[i]==k:
ans=max(i+1,ans)
for i in range(1,n):
for j in range(n-1,i-1,-1):
if preSum[j]-preSum[i-1]==k and j-i+1>=ans:
ans=max(j-i+1,ans)
break
return ans
前缀和+hashmap
- preSum字典存的是第一次出现和为key的子数组(从第一个数开始)的index+1。preSum初始的时候先把0放入,后面的每次偏移一位
- 例如
nums=1,-1,5,-2,3 ,k=3
则preSum={0: 0, 1: 1, 5: 3, 3: 4, 6: 5}
- 如果不先存0,则preSum={1: 0, 0: 1, 5: 2, 3: 3, 6: 4}
则1,-1,5,-2,3在遍历到index=3时,count=3,count-k=0,此时ans=i-preSum[count-k]=3-1=2,而不是4 - count存前缀和,即index=i时,存的是[0,i]的和
问题转换:因为最长子数组的起始位置不确定 故转换成求前面一段是否存在sum-k(起始位置为0)
preSum[j…i] = preSum[0…i] - preSum[0…j-1]
count-k + k = count找到第一次出现count-k的子数组的终止位置j, 则j+1到i为0到i区间上的最长子数组 长度为i-j
时间复杂度O(N) ,空间复杂度O(N)
class Solution:
def maxSubArrayLen(self, nums: List[int], k: int) -> int:
n=len(nums)
preSum={} #第一次出现和为key的子数组的index(0~index)
count=0
ans=0
preSum[0]=0
for i in range(n):
count=count+nums[i]
if count not in preSum:
preSum[count]=i+1
if count-k in preSum:
ans=max(ans,i-preSum[count-k]+1)
return ans