1553. 吃掉 N 个橘子的最少天数
大约 3 分钟
---
1553. 吃掉 N 个橘子的最少天数
- 标签:记忆化搜索、动态规划
- 难度:困难
题目链接
题目大意
描述:有 个橘子。每天可以选择:
- 吃掉 个橘子。
- 如果 能被 整除,吃掉一半( 个)。
- 如果 能被 整除,吃掉三分之二( 个,即剩 )。
要求:返回吃完所有橘子的最少天数。
说明:
- 。
示例:
- 示例 1:
输入:n = 10
输出:4
解释:你总共有 10 个橘子。
第 1 天:吃 1 个橘子,剩余橘子数 10 - 1 = 9。
第 2 天:吃 6 个橘子,剩余橘子数 9 - 2*(9/3) = 9 - 6 = 3。(9 可以被 3 整除)
第 3 天:吃 2 个橘子,剩余橘子数 3 - 2*(3/3) = 3 - 2 = 1。
第 4 天:吃掉最后 1 个橘子,剩余橘子数 1 - 1 = 0。
你需要至少 4 天吃掉 10 个橘子。- 示例 2:
输入:n = 6
输出:3
解释:你总共有 6 个橘子。
第 1 天:吃 3 个橘子,剩余橘子数 6 - 6/2 = 6 - 3 = 3。(6 可以被 2 整除)
第 2 天:吃 2 个橘子,剩余橘子数 3 - 2*(3/3) = 3 - 2 = 1。(3 可以被 3 整除)
第 3 天:吃掉剩余 1 个橘子,剩余橘子数 1 - 1 = 0。
你至少需要 3 天吃掉 6 个橘子。解题思路
思路 1:记忆化搜索 + 贪心剪枝
1. 核心思想
最大 ,无法线性 DP。必须用记忆化搜索 + 剪枝。
关键观察:
- 与其每天吃 个直到能被 或 整除,不如直接跳到最近的能被 或 整除的数。
- 状态转移:
- 每天吃 个 → 到 后整除 :。
- 这里的 表示先吃 天(每天 个),然后第 天执行除以 的操作。
严格定义递归:
- 如果 ,直接返回 。
- 。
2. 具体步骤
第 1 步:定义递归函数 。
- 如果 ,返回 。
- 如果已记忆化,直接返回。
- 。
- 存入记忆化,返回。
第 2 步:返回 。
3. 复杂度分析
状态数约为 ,因为每次递归 至少减半。
4. 举例说明
以 为例:
- ,;,。
- 。
- 。
- 。
- 。
- 。
验证:
- 方案:第 天吃 个(剩 ,能被 整除),第 天吃 个(剩 ),第 天吃 个(剩 ),第 天吃 个。 天。
另一种方案:
- (除以 ),(吃 ),(除以 ),(除以 ),(吃 )。 天。
最优为 天。
思路 1:代码
from functools import lru_cache
class Solution:
def minDays(self, n: int) -> int:
@lru_cache(None)
def dfs(n):
if n <= 1:
return n
return 1 + min(n % 2 + dfs(n // 2), n % 3 + dfs(n // 3))
return dfs(n)思路 1:复杂度分析
- 时间复杂度:,状态数约 个。
- 空间复杂度:,递归栈和哈希表。