动态规划与朴素递归的时间复杂度对比及DP解法正确性验证
木棍取走游戏:递归到动态规划的优化解析
一、takeDP解法的正确性验证
你的takeDP解法是正确的,核心逻辑和朴素递归一致,但通过记忆化存储避免了重复计算:
mem数组用于记录每个cur(当前已取木棍数)对应的最少剩余回合数,初始时全设为float("inf")表示该状态未被计算。- 当递归到某个
cur时,若mem[cur]已有有效值,直接返回结果,无需重复递归。 - 状态转移逻辑和朴素递归完全匹配:从当前
cur出发,取1、7、9根木棍后,取后续最少回合数的最小值加1(当前这一步操作),最终将结果存入mem[cur]。 - 注意调用前需正确初始化
mem数组(大小为pile+1,且mem[pile] = 0,因为当cur == pile时已取完所有木棍,回合数为0),否则初始调用takeDP(pile, 0, 0)无法得到正确结果。
二、复杂度从O(3^n)优化到O(n)的原因
朴素递归O(3^n)复杂度的根源
朴素递归take的问题在于大量重复计算:
- 每个状态
cur会衍生出3个分支(取1、7、9根),很多状态会被多次递归调用。比如cur=9会被cur=0(直接取9根)、cur=2(取7根)、cur=8(取1根)等多个前驱状态重复触发计算。 - 随着
n增大,重复计算的状态数呈指数级增长,最终时间复杂度达到O(3^n),这也是大数值n下递归效率极低的原因。
记忆化动态规划O(n)复杂度的逻辑
takeDP通过记忆化缓存彻底解决了重复计算问题:
- 总共有
n+1个不同的状态(cur从0到n),每个状态仅会被计算一次。 - 计算每个状态时,仅需完成3次最小值比较和赋值操作,时间开销为常数级。
- 因此总时间复杂度为O(n),每个状态仅处理一次,效率比朴素递归提升了数个数量级。
内容的提问来源于stack exchange,提问作者PhunkyPhil
相关产品推荐
相关产品推荐

