累加和为目标值的最长子数组、异或和为0的最大划分(注意思想)

思路
对每个位置进行考虑分析,然后从中找到最大的
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```

猜你喜欢

转载自blog.csdn.net/weixin_40876685/article/details/89016844