813:最大平均值的分组;有深搜和动态规划两种思路。深搜是自底向上,枚举分割点。动态规划是自上向下,从当前点往前找递推关系。深搜比较好理解,不用赋予初始值,因为是自底向上的,最后返回的是终点值。动态规划赋初始值的时候要小心。
5500. 乘积为正数的最长子数组长度
152. 乘积最大子数组
class Solution:
def maxProduct(self, nums: List[int]) -> int:
#最小的负数,最大的正数
min_val=nums[0]
max_val=nums[0]
res=nums[0]
for i in range(1,len(nums)):
cur_max_val=max(max_val*nums[i],min_val*nums[i],nums[i])
cur_min_val=min(min_val*nums[i],max_val*nums[i],nums[i])
max_val=cur_max_val
min_val=cur_min_val
res=max(res,max_val)
return res
53. 最大子序和
后面的结果如果为正就对当前有增益,否则直接舍弃。
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
dp=[0 for _ in range(len(nums))]
dp[0]=nums[0]
for i in range(1,len(nums)):
dp[i]=max(dp[i-1]+nums[i],nums[i])
return max(dp)
5982. 解决智力问题
377. 组合总和 Ⅳ
class Solution:
def combinationSum4(self, nums: List[int], target: int) -> int:
def dfs(target):
if target in cache:
return cache[target]
if target==0:
return 1
cur_ans=0
for i in range(len(nums)):
if target>=nums[i]:
cur_ans+=dfs(target-nums[i])
cache[target]=cur_ans
return cur_ans
cache={}
return dfs(target)
1981. 最小化目标值与所选元素的差
class Solution:
def minimizeTheDifference(self, mat: List[List[int]], target: int) -> int:
best = 10**9+7
m,n = len(mat),len(mat[0])
@lru_cache(None)
def dfs(cur,cursum):
nonlocal best,m,n
if best == 0:return
if cursum-target>=best:return
if cur == m:
if abs(cursum-target)<best:
best = abs(cursum-target)
return
for i in range(n):
dfs(cur+1,cursum+mat[cur][i])
dfs(0,0)
return best
作者:dianmei
链接:https://leetcode-cn.com/problems/minimize-the-difference-between-target-and-chosen-elements/solution/you-ya-de-bao-li-python-cache-by-dianmei-o35t/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
6011. 完成比赛的最少时间
class Solution:
def minimumFinishTime(self, tires: List[List[int]], changeTime: int, numLaps: int) -> int:
# 走一圈花费的最小时间
min_time = min([x[0] for x in tires])
# 遍历轮胎,计算同一个轮胎走各圈最小的时间
step_time = []
for f, r in tires:
t, x = 0, 0
# 如果走一圈的时间 > change+最快走一圈的时间,那么更换轮胎更快,继续用当前的走一定不是最优解,因此没有必要接着循环
while f * (r ** x) <= changeTime + min_time:
t += f * (r ** x)
if x == len(step_time):
step_time.append(t)
elif x < len(step_time) and step_time[x] > t:
step_time[x] = t
x += 1
# print(step_time)
# 计算走numLaps圈所需要的最小时间
dp = [0] * (numLaps+1)
for i in range(1, len(dp)):
temp = float("inf")
# 注意这里j=0表示走1圈用的时间,对应的是i=1
for j in range(len(step_time)):
if i - j < 1: break
# 如果i - j == 1, 说明是从第0圈直接走i圈的,不用加changeTime
if i - j == 1:
temp = min(temp, dp[i-j-1]+step_time[j])
else:
temp = min(temp, dp[i-j-1]+step_time[j]+changeTime)
dp[i] = temp
# print(dp)
return dp[-1]
作者:gang-gang-hao-6
链接:https://leetcode-cn.com/problems/minimum-time-to-finish-the-race/solution/pythondong-tai-gui-hua-by-gang-gang-hao-fhy5z/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution(object):
def minimumFinishTime(self, tires, changeTime, numLaps):
"""
:type tires: List[List[int]]
:type changeTime: int
:type numLaps: int
:rtype: int
"""
#先求单个轮胎跑x圈的最小耗时,中间不换胎。
#根据数据范围,最大值是15
# 走一圈花费的最小时间
min_time = [x[0] for x in tires]
costx=[float("inf") for _ in range(1001)]
for i in range(len(tires)):
cur=tires[i]
fi=cur[0]
ri=cur[1]
curtime=0
x=1
while fi*ri**(x-1)<=changeTime+min_time[i]:
curtime+=fi*ri**(x-1)
if curtime<costx[x]:
costx[x]=curtime
x+=1
# print(costx)
dp=[0 for _ in range(numLaps+1)]
for i in range(1,numLaps+1):
#中间不换胎
dp[i]=costx[i]
#在j处换胎。最后一个轮胎连续跑了j圈,爬楼梯的思想
for j in range(1,i+1):
dp[i]=min(dp[i],costx[j]+dp[i-j]+changeTime)
print(dp)
return dp[-1]
638. 大礼包
dfs+物品可重复使用
class Solution(object):
def shoppingOffers(self, price, special, needs):
"""
:type price: List[int]
:type special: List[List[int]]
:type needs: List[int]
:rtype: int
"""
def dfs(all_needs):
ans = 0
for i in range(len(all_needs)):
# 不用礼包
ans += price[i] * all_needs[i]
# 使用礼包
for j in range(len(special)):
libao = special[j]
# 判断是否可以使用这个礼包
flag = True
for h in range(len(all_needs)):
if libao[h] > all_needs[h]:
flag = False
if not flag:
continue
else:
# 使用当前礼包
price2 = libao[-1]
all_needs_next=[0 for _ in range(len(all_needs))]
for h in range(len(all_needs)):
all_needs_next[h] = all_needs[h] - libao[h]
ans = min(ans, dfs(all_needs_next) + price2)
return ans
return dfs(needs)
132. 分割回文串 II
回文串dp
class Solution:
def minCut(self, s: str) -> int:
isPalindromic=[[False]*len(s) for _ in range(len(s))]
for i in range(len(s)-1,-1,-1):
for j in range(i,len(s)):
if s[i]!=s[j]:
isPalindromic[i][j] = False
elif j-i<=1 or isPalindromic[i+1][j-1]:
isPalindromic[i][j] = True
# print(isPalindromic)
dp=[sys.maxsize]*len(s)
dp[0]=0
for i in range(1,len(s)):
if isPalindromic[0][i]:
dp[i]=0
continue
for j in range(0,i):
if isPalindromic[j+1][i]==True:
dp[i]=min(dp[i], dp[j]+1)
return dp[-1]
作者:carlsun-2
链接:https://leetcode-cn.com/problems/palindrome-partitioning-ii/solution/132-fen-ge-hui-wen-chuan-iidong-tai-gui-3hqva/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
没有预处理回文串的dp,超时
#dp[i]表示0到i至少分割多少次。
# leetcode submit region begin(Prohibit modification and deletion)
class Solution:
def minCut(self, s):
def check(a):
left=0
right=len(a)-1
while left<right:
if a[left]==a[right]:
left+=1
right-=1
else:
return False
return True
# if check(s):
# return 0
dp=[float("inf") for _ in range(len(s))]
dp[0]=0
for i in range(1,len(s)):
#先判断s[0:i+1]是不是回文
if check(s[:i+1]):
dp[i]=0
else:
for j in range(i):
cur=s[j+1:i+1]
if check(cur):
dp[i]=min(dp[i],dp[j]+1)
return dp[-1]
预处理回文串的dp
预处理就是把判断s[i:j](从i到j-1)是否是回文串,先用第5题的思路预处理出来。
#最长回文子串,思路:动态规划
# leetcode submit region begin(Prohibit modification and deletion)
class Solution:
def longestPalindrome(self, s):
max_len=0
start=0
end=0
dp=[[False for _ in range(len(s))] for _ in range(len(s))]
#初始化
# for i in range(len(s)):
# dp[i][i]=True
for i in range(len(dp)):
#收缩j
for j in range(i):
if s[j]==s[i]:
if i-j==1 or i-j==2:
dp[j][i]=True
else:
dp[j][i]=dp[j+1][i-1]
if dp[j][i]==True:
cur_len=i-j+1
if cur_len>max_len:
max_len=cur_len
start=j
end=i
return s[start:end+1]
s = "ccc"
res=Solution().longestPalindrome(s)
print(res)
class Solution:
def minCut(self, s: str) -> int:
def check(s):
dp = [[False for _ in range(len(s))] for _ in range(len(s))]
#一定要加上这个初始化条件,在第五题的时候不加这个条件可以过,但是在这个题里,会有bug,因为可以用到
for i in range(len(dp)):
dp[i][i] = True
for i in range(len(dp)):
# 收缩j
for j in range(i):
if s[j] == s[i]:
if i - j == 1 or i - j == 2:
dp[j][i] = True
else:
dp[j][i] = dp[j + 1][i - 1]
return dp
pre_dp = check(s)
dp = [float("inf") for _ in range(len(s))]
dp[0] = 0
for i in range(1, len(s)):
# 先判断0到i是不是回文
if pre_dp[0][i]:
dp[i] = 0
else:
for j in range(i):
if pre_dp[j + 1][i]:
dp[i] = min(dp[i], dp[j] + 1)
return dp[-1]
深搜
我的深搜做法如下,枚举分割点。但是这样有例子不通过。因为这种写法总是要返回一个1,没发考虑一下情况:当在c分割时,dd子串为0
class Solution(object):
def minCut(self, s):
"""
:type s: str
:rtype: int
"""
def dfs(i):
if i==len(s)-1:
return 0
res = float("inf")
#枚举分割点
for j in range(i,len(s)):
if s[i:j+1] == s[i:j+1][::-1]:
res = min(res,dfs(j+1) + 1)
return res
if s == s[::-1]:
return 0
return dfs(0)
class Solution:
def minCut(self, s: str) -> int:
@lru_cache(None)
def dfs(left, right):
if left > right:
return 0
# if s[left:right + 1] == s[left:right + 1][::-1]:
# return 0
if dp[left][right] == True:
return 0
res = float("inf")
# 枚举分隔点
for i in range(left, right):
#这种写法比下面那种写法减少了重复计算
if dp[left][i] == True:
res = min(res,dfs(i + 1, right) + 1)
# res = min(res, dfs(left, i) + dfs(i + 1, right) + 1)
return res
# 按照第五题预处理
def pre(s):
dp = [[False for _ in range(len(s))] for _ in range(len(s))]
for i in range(len(s)):
dp[i][i] = True
for i in range(len(s)):
for j in range(i):
if s[i] == s[j]:
if i - j == 1 or i - j == 2:
dp[j][i] = True
else:
dp[j][i] = dp[j + 1][i - 1]
return dp
dp = pre(s)
return dfs(0, len(s) - 1)
85 最大矩形
动态规划
逐个累加小块儿。最大正方形是累加边长,因为最大正方形的面积可以用边长*边长来计算。
class Solution {
public:
int maximalRectangle(vector<vector<char>>& matrix) {
int n = matrix.size();
int m = 0;
if (n > 0) { m = matrix[0].size(); }
vector<vector<int>> heights(n + 1,vector<int>(m + 1,0));
vector<vector<vector<int>>> dp(n + 1,vector<vector<int>>(m + 1, vector<int>(n + 1, 0)));
int ans = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (matrix[i-1][j-1] == '0') { continue; }
heights[i][j] = heights[i-1][j] + 1;
for (int k = 1; k <= heights[i][j]; k++) {
dp[i][j][k] = dp[i][j-1][k] + k;
ans = max(ans, dp[i][j][k]);
}
}
}
return ans;
}
};
作者:leeyupeng
链接:https://leetcode-cn.com/problems/maximal-rectangle/solution/dong-tai-gui-hua-by-leeyupeng-5/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution(object):
def maximalRectangle(self, matrix):
"""
:type matrix: List[List[str]]
:rtype: int
"""
#dp[i][j][k]表示以dp[i][j]为右下角,高度为k的矩形面积
dp=[[[0 for _ in range(len(matrix))] for _ in range(len(matrix[0]))] for _ in range(len(matrix))]
height=[[0 for _ in range(len(matrix[0]))] for _ in range(len(matrix))]
ans=0
for i in range(len(matrix)):
for j in range(len(matrix[0])):
#以(i,j)为最下端,的高度最大值
if matrix[i][j]=='0':
continue
height[i][j]=height[i-1][j]+1
for k in range(height[i][j]):
dp[i][j][k]=dp[i][j-1][k]+k+1
ans=max(ans,dp[i][j][k])
return ans
单调栈
221 最大正方形
动态规划
如果只考虑对角线
dp[i][j]=dp[i-1][j-1]+1,下图会考虑错。所以要同时考虑左边,上边和对角线。
class Solution(object):
def maximalSquare(self, matrix):
"""
:type matrix: List[List[str]]
:rtype: int
"""
max_bian=0
#dp[i][j]表示以i,j为右下角的正方形的边长
dp=[[0 for _ in range(len(matrix[0]))] for _ in range(len(matrix))]
#初始化最上边和最左边
for i in range(len(matrix)):
if matrix[i][0]=='1':
dp[i][0]=1
max_bian=max(max_bian,dp[i][0])
for j in range(len(matrix[0])):
if matrix[0][j]=='1':
dp[0][j]=1
max_bian=max(max_bian,dp[0][j])
for i in range(1,len(matrix)):
for j in range(1,len(matrix[0])):
if matrix[i][j]=='1':
dp[i][j]=min(dp[i-1][j-1],dp[i][j-1],dp[i-1][j])+1
max_bian=max(max_bian,dp[i][j])
return max_bian*max_bian
单调栈
1139. 最大的以 1 为边界的正方形
思路:dp[i][j]表示以i,j为右下角的最大正方形子网络,dp[i][j]等于往min(left的最大边长,往up的最大边长),因此要用两个dp数组,一个存left的最大边长,一个存right的最大边长。这样子得到的并不是实际上的最大子网络,因为另外两个边可能有0。
解决办法:以k=min(left的最大边长,往up的最大边长)为基准,搜另外两个边,如果另外两个边有0,就缩小当前的长度。
总结:
这个题和最大矩形有异曲同工之妙,最大矩形是从右下角,往上搜。
var largest1BorderedSquare = function(grid) {
const m = grid.length
const n = grid[0].length
const dpL = new Array(m+1).fill(0).map(()=>new Array(n+1).fill(0))
const dpU = new Array(m+1).fill(0).map(()=>new Array(n+1).fill(0))
var res = 0
//双重循环
for(var i = 1; i <= m; i++){ //以grid[i-1][j-1]为右下角的最大正方形的边长
for(var j = 1; j <= n; j++){
if(grid[i-1][j-1] === 0) continue
//1、以grid[i][j]结尾的连续1个数
dpL[i][j] = dpL[i][j-1] + 1
dpU[i][j] = dpU[i-1][j] + 1
const len = Math.min(dpL[i][j],dpU[i][j])
for(let k = len; k >=1; k--){
if(dpU[i][j+1-k] >= k && dpL[i+1-k][j] >= k){
res = Math.max(res,k) //代表边长
break
}
}
}
}
return res*res
};
410 分割子数组的最大值
动态规划
class Solution:
def splitArray(self, nums: List[int], m: int) -> int:
n = len(nums)
f = [[10**18] * (m + 1) for _ in range(n + 1)]
sub = [0]
for elem in nums:
sub.append(sub[-1] + elem)
f[0][0] = 0
for i in range(1, n + 1):
for j in range(1, min(i, m) + 1):
for k in range(i):
f[i][j] = min(f[i][j], max(f[k][j - 1], sub[i] - sub[k]))
return f[n][m]
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/split-array-largest-sum/solution/fen-ge-shu-zu-de-zui-da-zhi-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public int splitArray(int[] nums, int m) {
int n = nums.length;
int[][] f = new int[n + 1][m + 1];
for (int i = 0; i <= n; i++) {
Arrays.fill(f[i], Integer.MAX_VALUE);
}
f[0][0] = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= Math.min(i, m); j++) {
int s = 0;
for (int k = i-1; k >=0; k--) {
s += nums[k];
f[i][j] = Math.min(f[i][j], Math.max(f[k][j - 1], s));
}
}
}
return f[n][m];
}
}
深搜
class Solution:
def splitArray(self, nums: List[int], m: int) -> int:
@lru_cache(None)
def dfs(i,m):
if i == len(nums):#无法切分子数组
return float("inf")
elif m == 1:#子数组即为本身
# return sum(nums[i:])
return presum[-1] - presum[i]
res = float("inf")
s = 0
for j in range(i+1,len(nums)):
s += nums[j-1]
#剪枝,不加这个会超时。如果从起点到nums[j-1]的和,大于nums[j-1:],说明这个分割点已经不合格了,不用搜了
if s > presum[-1] - presum[j-1]:
break
res = min(res,max(dfs(j,m-1),s))
return res
presum = [0 for _ in range(len(nums)+1)]
# presum[0] = nums[0]
for i in range(1,len(nums)+1):
presum[i] = presum[i-1] + nums[i-1]
return dfs(0,m)
813. 最大平均值和的分组
动态规划
class Solution {
public double largestSumOfAverages(int[] nums, int k) {
int n = nums.length;
// dp[i][j] 表示把 nums 的前 i 项分为 j 组,得到的最大分数
double[][] dp = new double[n+1][k+1];
// 分成 0 组不成立。要设置为最小值,下面的dp[h-1][j - 1] + s / (i - h+1)就不会计算
// 但是当i=0,j=0时,dp[0][0]是为0的,这个不能说不成立,可以理解为虚拟哨兵节点,为了方便遍历。
for (int i = 1; i <= n; i++) {
dp[i][0] = Integer.MIN_VALUE;
}
//i和j都得从1开始遍历,为什么呢?
//因为,dp[0][j]表示把前0项分成j组,它是没有递推公式的,没有h。
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= Math.min(k, i); j++) {
double s = 0.0;
// 当前是第 j 组,前 j - 1 组是已经算好的
for (int h = i; h>= j; h--) {
s += nums[h-1];
dp[i][j] = Math.max(dp[i][j], dp[h-1][j - 1] + s / (i - h+1));
}
}
}
return dp[n][k];
}
}
深搜
class Solution:
def largestSumOfAverages(self, nums: List[int], k: int) -> float:
@lru_cache(None)
def dfs(i, k):
if i == len(nums):#无法切分子数组
return float("-inf")
elif k == 1:#子数组即为本身
return sum(nums[i:]) / (len(nums)-1 - i+1)
s = 0#求和
# j = i#剩余数组起始下标
res = float("-inf")
#枚举分割点,j点前面的不分割,j点及以后分割
for j in range(i+1,len(nums)):
s += nums[j-1]
res = max(res, s / (j - i) + dfs(j, k - 1))
return res
return dfs(0, k)
6059. 检查是否有合法括号字符串路径
回溯:超时
class Solution(object):
def hasValidPath(self, grid):
"""
:type grid: List[List[str]]
:rtype: bool
"""
def check(alist):
stack = [alist[0]]
for i in range(1, len(alist)):
if stack and alist[i] == stack[-1]:
stack.append(alist[i])
else:
if stack:
stack.pop()
else:
stack.append(alist[i])
if len(stack) == 0:
return True
return False
directions = [(1,0),(0,1)]
def dfs(start_x,start_y,left,right):
if right > left:
return False
if start_x == len(grid)-1 and start_y == len(grid[0])-1:
print(path)
if check(path):
return True
else:
return False
for direction in directions:
new_x = start_x + direction[0]
new_y = start_y + direction[1]
if new_x >= 0 and new_x <=len(grid)-1 and new_y >=0 and new_y <=len(grid[0])-1:
path.append(grid[new_x][new_y])
if grid[new_x][new_y] == "(":
left += 1
if grid[new_x][new_y] == ")":
right += 1
if dfs(new_x,new_y,left,right):
return True
path.pop()
return False
#特殊情况
path = []
path.append(grid[0][0])
if grid[0][0] == "(":
return dfs(0,0,1,0)
if grid[0][0] == ")":
return False
回溯+括号判断
只要不是带有list的回溯,是可以用lru_cache的。
注意一定要回溯,因为是在for循环里对值进行加减的
for direction in directions:
new_x = start_x + direction[0]
new_y = start_y + direction[1]
if new_x >= 0 and new_x <= len(grid) - 1 and new_y >= 0 and new_y <= len(grid[0]) - 1:
if grid[new_x][new_y] == "(":
left_count += 1
if grid[new_x][new_y] == ")":
right_count += 1
不回溯的话for循环会对left_count和right_count进行覆盖。
class Solution:
def hasValidPath(self, grid: List[List[str]]) -> bool:
directions = [(1,0),(0,1)]
@lru_cache(None)
def dfs(start_x,start_y,left_count,right_count):
if right_count > left_count:
return False
if start_x == len(grid) - 1 and start_y == len(grid[0]) - 1:
if left_count == right_count:
return True
else:
return False
for direction in directions:
new_x = start_x + direction[0]
new_y = start_y + direction[1]
if new_x >= 0 and new_x <= len(grid) - 1 and new_y >= 0 and new_y <= len(grid[0]) - 1:
if grid[new_x][new_y] == "(":
left_count += 1
if grid[new_x][new_y] == ")":
right_count += 1
if dfs(new_x, new_y, left_count,right_count):
return True
if grid[new_x][new_y] == "(":
left_count -= 1
if grid[new_x][new_y] == ")":
right_count -= 1
return False
if grid[0][0] == ")":
return False
return dfs(0,0,1,0)
记忆化深搜+括号判断
只有圆括号的情况下,不必用栈。判断方法是
左括号的数量最后与右括号相等,并且任意位置左括号数量一定不小于右括号数量。
不用回溯写法的话,不能在for循环里改变dfs的参数值
class Solution:
def hasValidPath(self, grid: List[List[str]]) -> bool:
@lru_cache(None)
def dfs(i, j, c):
if c < 0 or i == m or j == n:#当数量小于0或者超出边界则不合法
return False
c = c + 1 if grid[i][j] == "(" else c - 1#更新数量
return c == 0 if i == m - 1 and j == n - 1 else dfs(i + 1, j, c) or dfs(i, j + 1, c) #如果已经到了右下角则根据数量返回是否合法,否则继续深搜
m, n = len(grid), len(grid[0])
return dfs(0, 0, 0)
作者:qin-qi-shu-hua-2
链接:https://leetcode-cn.com/problems/check-if-there-is-a-valid-parentheses-string-path/solution/python-ji-yi-hua-shen-sou-by-qin-qi-shu-5yhnr/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
6069. 最大波动的子字符串
最大子数组中的变形
class Solution:
def largestVariance(self, s: str) -> int:
if s.count(s[0]) == len(s):
return 0
ans = 0
for a in ascii_lowercase:
for b in ascii_lowercase:
if b == a:
continue
diff, diff_with_b = 0, -inf
for ch in s:
if ch == a:
diff += 1
diff_with_b += 1
elif ch == b:
diff -= 1
diff_with_b = diff # 记录包含 b 时的 diff
if diff < 0:
diff = 0
if diff_with_b > ans:
ans = diff_with_b
return ans
作者:endlesscheng
链接:https://leetcode.cn/problems/substring-with-largest-variance/solution/by-endlesscheng-5775/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
剑指 Offer II 112. 最长递增路径
有递增条件不用加visited
class Solution:
def longestIncreasingPath(self, matrix: List[List[int]]) -> int:
directions = [(0,1),(0,-1),(1,0),(-1,0)]
@lru_cache(None)
def dfs(i,j):
cur_res = 1
for direction in directions:
new_x = i + direction[0]
new_y = j + direction[1]
if 0<=new_x<=len(matrix)-1 and 0<=new_y<=len(matrix[0])-1 and matrix[new_x][new_y] > matrix[i][j]:
cur_res = max(cur_res,dfs(new_x,new_y)+1)
return cur_res
res = 0
for i in range(len(matrix)):
for j in range(len(matrix[0])):
cur = dfs(i,j)
# print(i,j,cur)
res = max(cur,res)
return res
6110. 网格图中递增路径的数目
class Solution:
def countPaths(self, grid: List[List[int]]) -> int:
directions = [(-1,0),(1,0),(0,-1),(0,1)]
@lru_cache(None)
def dfs(row,col):
res = 1
for direction in directions:
new_row = row + direction[0]
new_col = col + direction[1]
if 0 <= new_row < len(grid) and 0 <= new_col < len(grid[0]):
if grid[new_row][new_col] > grid[row][col]:
#注意这里不要+1,因为求的是数量
res += dfs(new_row,new_col)
return res % (10**9+7)
count = 0
for i in range(len(grid)):
for j in range(len(grid[0])):
#以i,j为起点,的路径数目
count += dfs(i,j)
return count % (10**9+7)
6109. 知道秘密的人数
class Solution:
def peopleAwareOfSecret(self, n: int, delay: int, forget: int) -> int:
# 使用动态规划dp[i]表示第i+1天新知道秘密的人数
dp = [0]*n
dp[0] = 1
for i in range(n):
# 同时dp[i]能够在未来i+delay到min(i+forget, n)增加传播
for j in range(i+delay, min(i+forget, n)):
dp[j] += dp[i]
# 返回最后一天还没有忘记秘密的人数即前forget天新知道秘密的人数
return sum(dp[-forget:]) % (10**9+7)
作者:liupengsay
链接:https://leetcode.cn/problems/number-of-people-aware-of-a-secret/solution/er-xu-cheng-ming-jiu-xu-zui-by-liupengsa-bg37/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
6203. 矩阵中和能被 K 整除的路径
按余数分类动态规划
2400. 恰好移动 k 步到达某一位置的方法数目
class Solution:
def numberOfWays(self, startPos: int, endPos: int, k: int) -> int:
@lru_cache(None)
def dfs(pos,cur):
if pos == endPos and cur == 0:
return 1
if cur == 0:
return 0
return dfs(pos + 1,cur - 1) + dfs(pos -1 ,cur-1)
return dfs(startPos,k) % int(1e9 + 7)