动态规划(剪绳子、把数字翻译成字符串、礼物最大值、最长不重复字符串)

动态规划问题特点:

1 求最优解(乘积最大值,最多组合)

2 可分解成若干子问题的最优解(递归)

3 从上到下分析问题,从下到上求解问题

先求基础的子问题最优解——>保存这些最优解到一个数组——>依赖已求的子问题,求解整体最优解

#f(n)=max(f(i)*f(n-i)),0<i<length
fdef cut_rope(length):
    if length<2:return 0
    if length==2: return 1
    if length==3: return 2
    counts=[0]*(length+1)#存放子问题的最优解
    counts[0]=0
    counts[1]=1
    counts[2]=2
    counts[3]=3
    for i in range(4,length+1):
        maxnum=0
        for j in range(1,i//2+1): #需要取到i/2,所以range里面的时候用地板除,记得加一
            temp=counts[j]*counts[i-j]
            maxnum=max(maxnum,temp)
        counts[i]=maxnum
    return counts[length]

#递归问题,f(i)=f(i+1)+g(i,i+1)*f(i+2)
#动态规划,从后向前找
    
def Print(numbers):
    if numbers<0:
        print(None)
    return find(numbers)
def find(numbers):
    numbers=str(numbers)
    length=len(numbers)
    counts=[0]*length #记录子问题最优解
    for i in range(length-1,-1,-1):
        count=0
        if i==length-1:
            count+=1
        else:
            #通常情况f(i+1)种
            count+=counts[i+1]
            #判断,若i可以和i+1位组成两位数,且在0——25内,则g=1,增加f(i+1)
            #且该判断需在i < length-1的时候(i=length-1时i+2会出界)
            num=int(numbers[i])*10+int(numbers[i+1]) 
            if num>=0 and num<=25:
                count+=counts[i+2] if i<length-2 else 1
        counts[i]=count #从后向前依次更新
    return counts[0]

#No.47 礼物的最大值
#递归:f(i,j)=max(f(i-1,j),f(i,j-1))+values[i,j]
#用一个二维数组保存每个位置的最大值,最后返回[row,val]位置的值
def Maxvalue(matrix):
    row=len(matrix)
    col=len(matrix[0])
    Maxvalue=[[0]*col]*row
    
    for i in range(row):
        for j in range(col):
            up=0 #i=0时
            left=0 #j=0时
            if i>0:
                up=Maxvalue[i-1][j]
            if j>0:
                left=Maxvalue[i][j-1]
            maxnum=max(up,left)+matrix[i][j]
            Maxvalue[i][j]=maxnum
    return Maxvalue[-1][-1]
a=[[1,1,1],[2,3,1],[2,2,2]]
Maxvalue(a)

# 优化:只用一维数组保存每一行的最大值。f(i,j)不依赖于f(i-1,j-1)
def Maxvalue(matrix):
    row=len(matrix)
    col=len(matrix[0])
    Maxvalue=[0]*col 
    for i in range (row):
        for j in range(col):
            up=0
            left=0
            if i >0:
                up=Maxvalue[j]
            if j >0:
                left=Maxvalue[i-1]
            maxnum=max(up,left)+matrix[i][j]
            Maxvalue[j]=maxnum
    return Maxvalue[-1]

思路:
动态规划:
    遍历每一个字符串,计算以当前字符结尾的最长不重复子字符串的长度:并记录
    1 若前面没有和当前字符重复的:f(i)=f(i-1)+1
    2 前面有和当前重复的: 若重复的字符不在前一个字符串里面:则f(i)=f(i-1)+1;若重复的在前一个字符串里面:则f(i)=d(两个重复的字符的距离)

def Maxlength(string):
    string=[str(n) for n in string]
    length=len(string)
    Maplength=[0]*length #记录以每个字符为结尾的最长不重复字符串长度值
    for i in range(length):
        if i==0:
            curlength=1
        else:
            j=i-1
            Flag=False #记录是否重复,否则 d==i时,不知道是重复还是到首字符
            while j>=0:
                if string[j]==string[i]:
                    Flag=True
                    break
                j-=1
            d=i-j
            if (d==i and not Flag) or d >Maplength[i-1]: 
                #若不重复或者上一个重复的字符不在前一个连续不重复字符串里
                curlength=Maplength[i-1]+1
            else:
                #若重复,且重复字符在上一个不重复字符串里面
                curlength=d
        Maplength[i]=curlength
    return max(Maplength)
        
a=Maxlength('arabcacfr') 
#Maplength:[1, 2, 2, 3, 4, 3, 2, 3, 4]
# 4

上述方法两次遍历,时间复杂度O(n^{^{2}}),可以优化,用字典查找重复字符的位置更快

#优化:查找重复时不用遍历,用字典查找
def Maxlength(string):
    string=[str(n) for n in string]
    length=len(string)
    d={}
    if length==1:
        return 1
    curlength=1
    maxlength=1
    d[string[0]]=0 #用字典记录每个值的位置
    for i in range(1,length):
        if string[i] not in d:
            curlength+=1
        else:
            dist=i-d[string[i]] 计算距重复字符的距离
            if dist>curlength:
                curlength+=1
            else:
                maxlength=max(maxlength,curlength)
                curlength=dist
        d[string[i]]=i #每次都更新字符最后一次出现的位置
    return max(curlength,maxlength) #最后一个curlength没有加入maxlength

猜你喜欢

转载自blog.csdn.net/qq_43243022/article/details/88430477
今日推荐