参考灵神直播和代码
补充:DP 中常见的记忆化搜索 @cache 装饰器
@cache
装饰器的作用:将传入不同参数得到的函数值存储到缓存,避免下次传递相同参数重复计算结果,可用于解决递归函数重复计算问题,比如递归求斐波那契问题。
6899. 达到末尾下标所需的最大跳跃次数
https://leetcode.cn/problems/maximum-number-of-jumps-to-reach-the-last-index/
Solution
记忆化搜索
dfs(i)
表示以 nums[i]
为终点求的最大跳跃数
class Solution:
def maximumJumps(self, nums: List[int], target: int) -> int:
n = len(nums)
@cache
def dfs(i :int) -> int:
if i == 0:
return 0
res = -inf
for j in range(i):
if abs(nums[i] - nums[j]) <= target:
res = max(res, dfs(j) + 1)
return res
ans = dfs(n-1)
return ans if ans > 0 else -1
递推(逆向)
dp(i)
表示以 nums[i]
为终点求的最大跳跃数
class Solution:
def maximumJumps(self, nums: List[int], target: int) -> int:
n = len(nums)
dp = [-inf] * n
dp[0] = 0
for i in range(1, n):
for j in range(i):
if abs(nums[i] - nums[j]) <= target:
dp[i] = max(dp[i], dp[j] + 1)
return dp[-1] if dp[-1] > 0 else -1
递推(正向)
class Solution:
def maximumJumps(self, nums: List[int], target: int) -> int:
n = len(nums)
dp = [-1] * n
dp[0] = 0
for i in range(n):
if dp[i] >= 0: # 关键判断
for j in range(i + 1, n):
if abs(nums[j] - nums[i]) <= target:
dp[j] = max(dp[j], dp[i] + 1)
return dp[-1]
6912. 构造最长非递减子数组
https://leetcode.cn/problems/longest-non-decreasing-subarray-from-two-arrays/
Solution
记忆化搜索
dfs(i, 0/1)
表示以 nums1[i]
或者 nums2[i]
结尾的最大
class Solution:
def maxNonDecreasingLength(self, nums1: List[int], nums2: List[int]) -> int:
nums = (nums1, nums2)
@cache
def dfs(i: int, j: int) -> int:
if i == 0:
return 1
res = 1
# 如果 nums1[i-1] 符合条件
if nums1[i-1] <= nums[j][i]:
res = max(res, dfs(i - 1, 0) + 1)
# 如果 nums2[i-1] 符合条件
if nums2[i-1] <= nums[j][i]:
res = max(res, dfs(i - 1, 1) + 1)
return res
ans = 0
for i in range(len(nums1)):
ans = max(ans, dfs(i, 0), dfs(i, 1))
return ans
6919. 使数组中的所有元素都等于零
https://leetcode.cn/problems/apply-operations-to-make-all-array-elements-equal-to-zero/
Solution
差分数组
差分数组求前缀和即为各个区间的最终变化结果,差分数组可以把一个区间操作变为对两个数的操作,从而节省时间。
class Solution:
def checkArray(self, nums: List[int], k: int) -> bool:
n = len(nums)
d = [0] * (n + 1) # 差分数组
pre = 0 # 记录差分数组的前缀和, 边扫描, 边计算
for i, x in enumerate(nums):
pre += d[i]
x += pre
if x == 0:
continue
# x < 0 表示已经减到了负数, 不符合要求
# i + k > 0 表示越界了, 不符合要求
if x < 0 or i + k > n:
return False
# 差分过程
pre -= x
d[i+k] += x
return True
6923. 将字符串分割为最少的美丽子字符串
https://leetcode.cn/problems/partition-string-into-minimum-beautiful-substrings/description/
相关题目
131. 分割回文串文章来源:https://www.toymoban.com/news/detail-542288.html
Solution
记忆化搜索
dfs(i)
表示从 s[i]
到 s[n-1]
最少分割成多少段文章来源地址https://www.toymoban.com/news/detail-542288.html
class Solution:
def minimumBeautifulSubstrings(self, s: str) -> int:
pow5 = [bin(5**i)[2:] for i in range(10) if len(bin(5**i)[2:]) <= 15]
n = len(s)
@cache
def dfs(i :int) -> int:
if i == n:
return 0
if s[i] == '0': # 表示不合法的状态
return inf
res = inf
# 遍历 5 的幂二进制串, 看选哪一个
for t in pow5:
if i + len(t) > n:
break
if s[i:i + len(t)] == t:
res = min(res, dfs(i + len(t)) + 1)
return res
ans = dfs(0)
return ans if ans < inf else -1
到了这里,关于[LeetCode108双周赛&LeetCode353周赛] 学习用记忆化搜索解决 DP 问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!