题目描述
找到所有上升子串的数量,很明显dfs,在找长度为3肯定会用到长度为2的子串存在重叠子问题,优化用记忆化搜索,
for循环每一点的上升子串的数目都搜出来记录下来,最终求和f
f[x][y]代表x y 点出发的上升子串数目
注意这里的一个区别,就是进入下一层dfs之前f[x][y]=1,因为一个字符也算
M,N=510,510
f=[[-1]*10 for i in range(10)]#代表x y 点出发的上升子串数目
dire=[[1,0],[-1,0],[0,1],[0,-1]]
mat=[["A","B","C"],["B","C","A"]]
n,m=2,3
def dfs(x,y):#以x,y为起点搜索以该点为起点的所有上升序列的长度记录在fx,y中
global n,m
if f[x][y]!=-1:return f[x][y]
f[x][y]=1#本身算一个 ,注意这里和其他记忆化搜索的区别!!!
for d in dire:
nx,ny=x+d[0],y+d[1]
#print((x,y),"=>",(nx,ny))
if 0<=nx<n and 0<=ny<m and mat[nx][ny]>mat[x][y] :#d第一次写 范围写错了,注意!
f[x][y]+=dfs(nx,ny)
return f[x][y]
ans=0
for i in range(0,n):
for j in range(0,m):
ans += dfs(i,j)
print(ans)
cnt=0
for i in range(0,n):
for j in range(0,m):
if f[i][j]==-1:continue
cnt +=f[i][j]
print(cnt)
朴素的dfs写法
肯定要先写退出条件,一开始想到搜到 最左下角就退出,但是这样会少搜了以左下角为起点向四周的结果;而且因为上升子串的长度不唯一,每次结束的条件都不一样,不像是n皇后,搜到n行就可以退出,如果要真的写,为dfs携带参数,记录数目。。。。好像也不太好写,最好的还是dfs一点就记录在备忘录里
我们的target是记录所有点的上升序列,而上升序列最长也就26!
我们让dfs携带参数target 目标长度,和当前长度count ,如果target==count 就说明找到,记录一次!这便是递归的出口!!!!!
我们遍历所有上升序列长度的可能性,1-26,再遍历每一个点的上升序列长度,累加!
参考别人思路写的一个朴素的dfs,效率挺低
dire=[[1,0],[-1,0],[0,1],[0,-1]]
mat=[["A","B","C"],["B","C","A"]]
n,m=2,3
summ=0
def dfs(x,y,count,target):
global summ,n,m
if count == target:
#print(count)
summ+=1
else:
for d in dire:
nx,ny=x+d[0],y+d[1]
#print((x,y),"=>",(nx,ny))
if 0<=nx<n and 0<=ny<m and mat[nx][ny]>mat[x][y]:
#print((nx,ny),"==")
count +=1
dfs(nx,ny,count,target)
count -=1
for target in range(1,27):
for i in range(0,n):
for j in range(0,m):
dfs(i,j,1,target)
print(summ)