动态规划——解决递归痛点

动态规划与递归的关系

  • 递归与动态规划是两个刚好相反但是解题思路相同的过程。
  • 两个方法都是通过把一个大的问题化小,小到可以一步解决,递归是采用从顶层 层层递归,知道递归出口之后得到结果。
  • 递归的痛点是重复计算重复子问题
    以斐波那契数列为例,用递归会重复计算左右分支的结点,时间复杂度2^n.
    动态规划的优势就体现出来了,将计算过的值都记忆了。
    斐波那契数列

递归协助解决动态规划

  1. 写出大规模问题和子问题的递推关系式
  2. 找到递归出口
  3. 设计动态规划数组
  4. 编写代码

示例:相加和为9

给一个int型数组arr,选择若干数字,若相加能得到数s,则返回True,否则返回False。
在这里插入图片描述

找递推关系

在这里插入图片描述
接下来讨论是否选择arr[4],只有选和不选两种结果。

subset(arr[i], s)
subset(arr[5], 9) = subset(arr[4], 7) or subset(arr[4], 9)

递归出口
subset(arr[i], s)
  1. 处理过程中发现 s == 0,说明已经可以返回True,接下来不需要找了
if s == 0return True
  1. 当数组找啊找只剩下最后一个数字arr[0]时,直接比较arr[0]是否与最终要凑的s相等,若相等返回True。
if i == 0:
	return arr[0] == s
  1. 当找到的数比s大,比如选了34就不可能凑到9,那么这个时候只有一种选择,就是不选它,相当于直接将其从数组移除
if arr[i] > s:
	return subset(arr[i-1], s)
(递归代码已经出来了)
def rec_subset(arr, i, s):
    if s == 0:
        return True
    elif i == 0:
        return arr[0] == s
    elif arr[i] > s:
        return rec_subset(arr, i-1, s)
    else:
        A = rec_subset(arr, i-1, s - arr[i])
        B = rec_subset(arr, i-1, s)
        return A or B

设计动态规划数组

第一横排对应第一个出口
第一个竖排对应第二个出口
在这里插入图片描述

动态规划程序
import numpy as np
def dp_subset(arr, s):
    subset = np.zeros((len(arr), s+1), dtype=bool)
    subset[:, 0] = True # 第一横排
    subset[0, :] = False # 第一列
    subset[0, arr[0]] = True # 左上角为True
    for i in range(1, len(arr)):
        for s in range(1, s+1):
            if arr[i] > s:
                subset[i, s] = subset[i-1, s]
            else:
                A = subset[i-1, s - arr[i]]
                B = subset[i-1, s]
                subset[i, s] = A or B
    r, c = subset.shape # 返回这个numpy的行列数
    return subset[r-1, c-1] # 返回右下角的值即结果
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值