最大上升子序列(lis)=以i为结尾的最大长度=一维坐标=接龙型动态规划=坐标型动态规划
dp【i】:表示以第i个数为龙尾的最长的龙有多长
dp【i】=max{dp【j】+1},j<i&&nums【j】<nums【i】
initialization:dp【0..n-1】=1
answer:max{dp【0..n-1】
1,最长上升子序列(非连续)
if not nums:#特殊情况
return 0
n=len(nums)
dp=[1]*n
for i in range(n):
for j in range(i):
if nums[i]>nums[j]:
dp[i]=max(dp[i],dp[j]+1)
return max(dp)
定义dp[i]:以下标为i结尾的最长上升子序列的最大值,
for j in range(i):是让i与前面的如何一个数比较大小,若大于则在前面的数长度基础上加一
因为只有一个方向(从左到右),故不用进行升序排序。
如果要求返回最优解的其中一个结果
if not nums:#特殊情况
return 0
n=len(nums)
dp=[1]*n
prev=[-1]*n
for i in range(n):
for j in range(i):
if nums[i]>nums[j] and dp[i]<dp[j]+1:
#只有满足dp[i]<dp[j]+1时,才进行,dp[i]=dp[j]+1和prev[i]=j
#max(dp[i],dp[i]=dp[j]+1)则无法限制prev[i]=j
dp[i]=dp[j]+1
prev[i]=j
longest,last=0,-1
for i in range(n):
if dp[i]>longest:
longest=dp[i]
last=i
path=[]
while last!=-1:
path.append(nums[last])
last=prev[last]
return longest,path[::-1]
2,最长上升连续子序列
if not a:#特殊情况的判断
return 0
n=len(a)
dp=[1]*n
dq=[1]*n
for i in range(1,n):
if a[i]>a[i-1]:
dp[i]=dp[i-1]+1
for i in range(1,n):
if a[i]<a[i-1]:
dq[i]=dq[i-1]+1
return max(max(dp),max(dq))
3,最长上升连续子序列 II
if not matrix:#特殊情况
return 0
n,m=len(matrix),len(matrix[0])
a=[]
for i in range(n):
for j in range(m):
a.append((matrix[i][j],i,j))
a.sort()
dp=[[1]*m for i in range(n)]
for i in range(len(a)):
x=a[i][1]
y=a[i][2]
for dx,dy in [(1,0),(0,1),(-1,0),(0,-1)]:
#因为是连续的,所以只能走一步,故没有j的循环
x1=x+dx
y1=y+dy
if 0<=x1<n and 0<=y1<m and matrix[x][y]>matrix[x1][y1]:
dp[x][y]=max(dp[x][y],dp[x1][y1]+1)
mx=0
for i in range(n):
mx=max(mx,max(dp[i]))
return mx
对于一个矩阵型的最大上升子序列,每一个坐标的四个方向都是他的子问题,将他们四个与自己进行打擂台,即可选出最优解。
但是在顺序上面,因为每个坐标都可以是起点,而大的值不仅依赖于四个方向,还依赖于比他小的值,因此要先排序,再从小到大进行遍历,然后再遍历四个方向。
在此题的基础上写
最长上升连续子序列
if not a:#特殊情况的判断
return 0
n=len(a)
m=[]
for i in range(n):
m.append((a[i],i))
m.sort()
dp=[1]*n
for i in range(n):
x=m[i][1]
for dx in [1,-1]:#因为连续,只能走一步
x1=dx+x
if 0<=x1<n and a[x]>a[x1]:
dp[x]=max(dp[x],dp[x1]+1)
return max(dp)
4,最大整除子集
会超时
if not nums:
return []
n=len(nums)
dp=[1]*n
prev=[-1]*n
nums.sort()
for i in range(n):
for j in range(i):
if nums[i]%nums[j]==0 and dp[i]<dp[j]+1:
dp[i]=dp[j]+1
prev[i]=j
longest,last=0,-1
for i in range(n):
if dp[i]>longest:
longest=dp[i]
last=i
l1=[]
while last!=-1:
l1.append(nums[last])
last=prev[last]
return l1[::-1]
优化
if not nums:
return []
n=len(nums)
dp={}
prev={}
for num in nums:
dp[num]=1
prev[num]=-1
nums.sort()
def factors(x):
if x==1:
return []
l=[]
i=1
while i*i<=x:
if x%i==0:
l.append(i)
if i*i!=x and i!=1:
l.append(x//i)
i+=1
return l
for num in nums:
for factor in factors(num):
if factor in dp:
if dp[num]<dp[factor]+1:
dp[num]=dp[factor]+1
prev[num]=factor
longest,last=0,-1
for num in nums:
if dp[num]>longest:
longest=dp[num]
last=num
l1=[]
while last!=-1:
l1.append(last)
last=prev[last]
return l1[::-1]