思路:
对每个位置进行考虑分析,然后从中找到最大的
1、累加和为目标值的最长子数组(哈希表)
奇数偶数长度相等的最长子数组(奇数为1,偶数为-1,求累加和为0的最长子数组)
def longestSumArray(arr,k): #k为目标值
dict={} #记录每个位置的累加和,key为累加和,value为当前位置
ll=0 #输出
summ=0
dict[0]=-1 #重要步骤,位置-1的累加和为0
for i in range(len(arr)):
summ+=arr[i]
if summ-k in dict: #sum-k出没出现过
ll=max(i-dict[summ-k],ll) #出现过,长度则为i-dict[summ-k],没出现过,长度为0
if summ not in dict: #更新dict,累加和出现过不更新
dict[summ]=i
return ll
arr=[7,3,2,1,1,7,-6,-1,7]
print(longestSumArray(arr,7))
1(2)累加和为目标值的最大子数组(仅有正数):双指针法【单调性】
def maxlen(arr,aim):
if not arr or len(arr)==0 or aim<=0:
return 0
l=0
r=0
summ=arr[0]
res=0 #最大子数组长度
while r<len(arr):
if summ==aim:
res=max(res,r-l+1)
summ-=arr[l] #左边继续往下走,遍历下一个位置
l+=1
elif summ<aim:
r+=1
if r==len(arr): #保证r不越界
break
summ+=arr[r]
else: #summ>aim
summ-=arr[l]
l+=1
return res
1(3)累加和小于目标和的最长子数组(可正可负可0)
时间复杂度O(N)
两个列表:
(1)以每个位置开头的最小累加和,从后往前,可复用信息
(2)对应的右边界
然后从第一个位置计算结果,过程中通过舍掉无效答案来进行优化
def maxlenless(arr,aim):
if not arr or len(arr)<1:
return 0
minsum=[0]*len(arr) #最小累加和数组
minsumindex=[0]*len(arr) #累加和对应的右边界
minsum[len(arr)-1]=arr[len(arr)-1]
minsumindex[len(arr)-1]=len(arr)-1
for i in range(len(arr)-2,-1,-1): #求两个数组,遍历一遍即可得到,时间复杂度O(N)
if minsum[i+1]<0: #后一个的最小累加和小于0,往右扩
minsum[i]=arr[i]+minsum[i+1]
minsumindex[i]=minsumindex[i+1]
else: #大于0,不扩
minsum[i]=arr[i]
minsumindex[i]=i
r=0
su=0
res=0
for l in range(len(arr)):
while r<len(arr) and su+minsum[r]<=aim: #小于aim值,可以扩
su+=minsum[r]
r=minsumindex[r]+1
if r>l: #当前区域有值
su-=arr[l]
else: #当前窗口没有值
su-=0
res=max(res,r-l)
r=max(r,l+1)
return res
2、异或和为0的最大划分
具体思想参考:
https://blog.csdn.net/qjh5606/article/details/88675806
def most_eor(arr):
eor=0
dp=[0 for i in range(len(arr))] #每个位置上的最大划分次数
dict={} #位置的下标(value),和对应的异或和(key)
dict[0]=-1 #-1位置上设为0,关键
res=0
for i in range(len(arr)):
eor^=arr[i]
if eor in dict:
pre=dict[eor]
if pre==-1:
dp[i]=1
else:dp[i]=dp[pre]+1
if i>0:
dp[i]=max(dp[i-1],dp[i]) #两种情况(1)当前点的区域异或和为0(2)不为0
dict[eor]=i #覆盖原来记录,异或和为sum的离最近的点
res=max(res,dp[i])
return res```