【LeetCode:2742. 给墙壁刷油漆 + 递归 + 记忆化搜索 + dp】

在这里插入图片描述

🚀 算法题 🚀

🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀
🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨
🌲 作者简介:硕风和炜,优快云-Java领域优质创作者🏆,保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文|经验分享|好用的网站工具分享💎💎💎
🌲 恭喜你发现一枚宝藏博主,赶快收入囊中吧🌻
🌲 人生如棋,我愿为卒,行动虽慢,可谁曾见我后退一步?🎯🎯

🚀 算法题 🚀

在这里插入图片描述
在这里插入图片描述

🚩 题目链接

⛲ 题目描述

给你两个长度为 n 下标从 0 开始的整数数组 cost 和 time ,分别表示给 n 堵不同的墙刷油漆需要的开销和时间。你有两名油漆匠:

  • 一位需要 付费 的油漆匠,刷第 i 堵墙需要花费 time[i] 单位的时间,开销为 cost[i] 单位的钱。
  • 一位 免费 的油漆匠,刷 任意 一堵墙的时间为 1 单位,开销为 0 。但是必须在付费油漆匠 工作 时,免费油漆匠才会工作。

请你返回刷完 n 堵墙最少开销为多少。

示例 1:

输入:cost = [1,2,3,2], time = [1,2,3,2]
输出:3
解释:下标为 0 和 1 的墙由付费油漆匠来刷,需要 3 单位时间。同时,免费油漆匠刷下标为 2 和 3 的墙,需要 2 单位时间,开销为 0 。总开销为 1 + 2 = 3 。
示例 2:

输入:cost = [2,3,4,2], time = [1,1,1,1]
输出:4
解释:下标为 0 和 3 的墙由付费油漆匠来刷,需要 2 单位时间。同时,免费油漆匠刷下标为 1 和 2 的墙,需要 2 单位时间,开销为 0 。总开销为 2 + 2 = 4 。

提示:

1 <= cost.length <= 500
cost.length == time.length
1 <= cost[i] <= 106
1 <= time[i] <= 500

🌟 求解思路&实现代码&运行结果


⚡ 递归 + 记忆化搜索 + dp

🥦 求解思路
  1. 思路1,设计一个三个参数的递归参数dfs(i,cnt,t)来返回最少开销。其中i表示当前来到的当前位置,cnt表示此时选择了多少个付费的工人,t表示付费工人的工作时间。遍历数组,每个位置可以选择或者不选。最终返回最小的开销。这样做,需要枚举的状态太多了,即使是缓存,也会超限,所以,需要继续优化。
  2. 思路2,在思路1的基础上,减少状态,dfs(i,t)来返回最少开销。i表示来到当前的位置,此时t表示后续还可以雇佣的免费工人,和思路1的区别在于,思路1的时间是只记录付费工人时间,思路2需要做的不仅仅是付费工人时间,免费工人也需要记录,实现时如果当前位置选,加当前位置的时间,如果不选,此时的位置需要交给免费工人来做,直接减1。最后,如果当前的 t > n - 1 - i,表示无需进行后续的过程,找到了一种开销。结果返回众多开销中最小的即可。
  3. 有了基本的思路,接下来我们就来通过代码来实现一下。
🥦 实现代码
class Solution {
   
   
    int[] cost;
    int[] time;
    int[][] map;
    int n;

    public 
<think>好的,用户之前问过斐波那契数列递归的时间复杂度,现在又接着问记忆化递归。这说明他们对优化递归方法感兴趣,可能在实际编程中遇到了性能问题,想了解如何改进。 用户可能是刚开始学习算法,或者在做项目时发现递归太慢,想知道怎么优化。他们可能已经知道朴素递归的问题,现在需要更高效的解决方案。记忆化递归作为常见的优化手段,用户想了解它的原理和实现方式。 我需要先解释记忆化递归是什么,然后对比普通递归的区别,强调如何通过缓存结果减少重复计算。要给出具体的例子,比如斐波那契数列的实现,展示代码的变化,并分析时间复杂度的提升。可能用户还想知道适用场景和注意事项,比如哪些问题适合用记忆化,以及空间复杂度的问题。 另外,用户可能对动态规划和记忆化的关系不太清楚,需要简单说明。还要提到可能的缺点,比如额外的空间开销,但相对于时间优化来说是值得的。确保语言通俗易懂,避免太专业的术语,用例子帮助理解。</think>### 记忆化递归(Memoization)详解 --- #### 1. **核心思想** **记忆化递归**是一种优化递归算法的技术,通过**缓存(存储)已计算的子问题结果**,避免重复计算,从而将指数级时间复杂度优化为线性级。其核心逻辑为: - **记录历史**:每次计算新问题时,先检查是否已存储答案 - **避免重复**:若已存储,直接返回缓存结果;若未存储,计算后缓存 --- #### 2. **与朴素递归的对比** 以斐波那契数列为例: | 方法 | 计算过程示意图 | 时间复杂度 | |------------|---------------------------------------|------------| | 朴素递归 | ![朴素递归树](https://example.com/普通递归树) | $O(\phi^n)$ | | 记忆化递归 | ![优化递归树](https://example.com/记忆化递归树) | $O(n)$ | **关键差异**: - 记忆化递归将树状递归结构转化为**线性链式调用** - 每个子问题仅计算一次 --- #### 3. **实现步骤(以Python为例)** ##### (1) 基础版记忆化(手动缓存) ```python def fib_memo(n, memo={}): if n <= 1: return n if n not in memo: memo[n] = fib_memo(n-1, memo) + fib_memo(n-2, memo) return memo[n] ``` ##### (2) 使用装饰器自动记忆化(Python标准库) ```python from functools import lru_cache @lru_cache(maxsize=None) def fib(n): if n <= 1: return n return fib(n-1) + fib(n-2) ``` --- #### 4. **时间复杂度分析** - **未优化时**:$T(n) = T(n-1) + T(n-2) + O(1) \rightarrow O(\phi^n)$ - **记忆化后**:每个 $F(k)$ 仅计算一次 总操作次数 = $n + 1$(从 $F(0)$ 到 $F(n)$) **时间复杂度降至**:$O(n)$ --- #### 5. **空间复杂度分析** - **存储空间**:需要 $O(n)$ 的缓存空间存储所有计算结果 - **调用栈深度**:最坏情况下递归深度为 $O(n)$(例如计算 $F(n)$ 时调用链为 $F(n) \rightarrow F(n-1) \rightarrow ... \rightarrow F(0)$) --- #### 6. **适用场景** | 场景类型 | 示例问题 | |--------------------|-------------------------| | 重叠子问题 | 斐波那契数列、爬楼梯问题 | | 无后效性问题 | 背包问题(部分变体) | | 树形/图结构遍历优化 | 二叉树路径统计 | --- #### 7. **注意事项** 1. **缓存策略选择**: - 使用字典手动控制(灵活) - 使用 `lru_cache` 装饰器(便捷,但需注意可变参数问题) 2. **递归深度限制**: - Python默认递归深度约1000层,超限需用 `sys.setrecursionlimit()` - 对极大 $n$ 仍可能栈溢出,此时应改用迭代法 3. **副作用问题**: - 缓存可能导致函数非纯(依赖外部状态) - 对有副作用的函数慎用记忆化 --- #### 8. **与动态规划的关系** | 特性 | 记忆化递归 | 动态规划 | |--------------|--------------------------|-----------------------| | 计算方向 | 自顶向下(Top-down) | 自底向上(Bottom-up) | | 实现方式 | 递归 + 缓存 | 迭代 + 状态表 | | 空间占用 | 需要存储全部中间结果 | 可优化状态存储维度 | | 适用问题特征 | 子问题边界不明显时更易实现 | 适合结构化递推问题 | --- #### 9. **总结** **记忆化递归的本质是“用空间换时间”**,通过以下步骤实现优化: 1. 识别重叠子问题 2. 设计缓存数据结构 3.递归调用前检查缓存 4. 递归返回时更新缓存 典型时间复杂度对比: - 斐波那契数列:从 $O(1.618^n)$ → $O(n)$ - 爬楼梯问题:从 $O(2^n)$ → $O(n)$ **适用原则**:当递归算法存在大量重复计算,且存储中间结果不会导致空间爆炸时,优先选择记忆化递归
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

硕风和炜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值