返回
从递归到动态规划,走进算法之美——leetcode 2140 题解
后端
2024-01-03 05:55:04
从递归到动态规划,走进算法之美——leetcode 2140 题解
算法之美,在于其简洁、高效,以及解决问题时思路的灵光乍现。leetcode 上的题目,正是一个个考验算法能力的练兵场。今天,我们就来共同探索 leetcode 第 2140 题的解题思路,从递归到动态规划,领略算法的魅力。
题目
给你一个整数数组 questions,其中 questions[i] 是你解决第 i 个问题需要花费的时间。同时给你一个整数 brainpower,是你的脑力值。每一分钟,你可以解决一个问题,每当你的脑力值低于或等于 0 时,你就会疲惫不堪并失去解决问题的动力。
你想要找到解决所有问题需要花费的 最短时间 。
示例:
输入:questions = [3,2,5,4,1], brainpower = 10
输出:7
解释:第一分钟解决第一个问题,脑力值变为 7。第二分钟解决第二个问题,脑力值变为 5。第三分钟解决第四个问题,脑力值变为 1。第四分钟解决第五个问题,脑力值变为 0。第五分钟解决第三个问题,脑力值变为 5。第六分钟和第七分钟分别解决第六个和第七个问题,脑力值变为 0。
因此,解决所有问题需要花费 7 分钟。
题解:
方法一:递归解法
递归的思路很简单,就是穷举所有可能的情况,直到找到最优解。具体步骤如下:
- 尝试解决第一个问题,此时脑力值变为 brainpower - questions[0]。
- 递归求解剩余问题,并将结果与当前解进行比较,取最优解。
- 回溯,尝试解决下一个问题,重复步骤 1 和 2。
这种方法看似可行,但遗憾的是,它在实际运行时会超时。究其原因,在于递归的计算过程过于冗余,重复计算了大量子问题。为了解决这个问题,我们需要引入一种更有效的方法——动态规划。
方法二:动态规划解法
动态规划是一种自底向上的求解方法,它通过存储子问题的解,避免重复计算。对于本题,我们可以定义一个二维数组 dp,其中 dp[i][j] 表示解决前 i 个问题,且脑力值为 j 时的最短时间。
def min_time(questions, brainpower):
"""
:type questions: List[int]
:type brainpower: int
:rtype: int
"""
n = len(questions)
# 初始化 dp 数组
dp = [[float('inf') for _ in range(brainpower + 1)] for _ in range(n + 1)]
# 设置边界条件
dp[0][brainpower] = 0
# 迭代求解 dp 数组
for i in range(1, n + 1):
for j in range(brainpower, -1, -1):
# 尝试解决当前问题
if j >= questions[i - 1]:
dp[i][j] = min(dp[i - 1][j], dp[i - 1][j - questions[i - 1]] + 1)
# 不解决当前问题
else:
dp[i][j] = dp[i - 1][j]
# 返回最短时间
return dp[n][brainpower]
时间复杂度:
动态规划的解法时间复杂度为 O(n * brainpower),其中 n 是问题数量,brainpower 是脑力值的上限。
总结:
动态规划是一种强大的算法技术,它可以有效地解决许多递归问题。leetcode 上的题目,为我们提供了绝佳的练习机会,让我们在实战中不断磨练算法技巧。希望本文对您有所帮助,也欢迎您在评论区留下您的想法和建议。