python 记忆化剪枝
剪枝
剪枝一种可以提高搜索算法时间和空间效率的技巧,经过剪枝和其他优化策略优化过的算法在执行效率上远超一般未经剪枝的算法。甚至有些暴力搜索过不了时限的算法,也可以通过各种剪枝+优化大大缩短算法运行时间,成功通过时效限制。
如图:
剪枝的常见方法
可行性剪枝
所谓可行性剪枝,就是如当前状态和题意不符,并且由于题目可以推出,往后的所有情况和题意都不符,那么就可以进行剪枝,直接把这种情况及后续的所有情况判负,直接返回。
排除等效冗余
所谓排除等效冗余,就是当几个枝桠具有完全相同的效果的时候,只选择其中一个走就可以了。
最优性剪枝
所谓最优性剪枝,是在我们用搜索方法解决最优化问题的时候的一种常用剪枝方法。当搜到一半的时候,发现比已经搜索到的最优解差,则该方案肯定是不行的,即刻停止搜索,进行回溯。
顺序剪枝
普遍来讲,搜索的顺序是不固定的,对一个问题来讲,算法可以进入搜索树的任意的一个子节点。但假如我们要搜索一个最小值,而非要从最大值存在的那个节点开搜,就可能存在搜索到最后才出解。而我们从最小的节点开搜很可能马上就出解。这就是顺序剪枝的一个应用。一般来讲,有单调性存在的搜索问题可以和贪心思想结合,进行顺序剪枝。
记忆化
记忆化搜索其实是搜索的另外一个分支。就是记录搜索的每一个状态,当重复搜索到相同的状态的时候直接返回。
记忆化搜索
这次实现的是记忆化搜索的装饰器,一般用在递归上。下面是装饰器代码:
def jian_zhi(func):
# 中间字典,判断已经是否求解过
median = {}
def wrap(*args):
# 假如不在中间字典中,说明没有求解过,添加到字典中去,在的话,直接返回
if args not in median:
median[args] = func(*args)
return median[args]
return wrap
简单例子
举一个简单的例子,是leetcode上的一道题目:爬楼梯。爬楼梯有更优的解题算法(用公式+动态规划做)
本次就用递归+剪枝来做。下面是题目
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
例1:输入:n = 2 输出:2
解释:有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶
例2:输入:n = 3 输出:3
解释:有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶
提示:
1 <= n <= 45
以下我们用递归的方式解决这道
def jian_zhi(func):
# 中间字典,判断已经是否求解过
median = {}
def wrap(*args):
# 假如不在中间字典中,说明没有求解过,添加到字典中去,在的话,直接返回
if args not in median:
median[args] = func(*args)
return median[args]
return wrap
class Solution(object):
@jian_zhi # 剪枝装饰器
def climbStairs(self, n):
"""
:type n: int
:rtype: int
"""
if n <= 3:
rtype = n
else:
rtype = 0
# 这里我们用递归的方式,当N小于3,我们直接能知道答案,当N大于3我们有两种决策路线
rtype = rtype + self.climbStairs(n-1) + self.climbStairs(n-2)
return int(rtype)
当我们如果不用装饰器,在leetcode上会超时无法计算出结果;而用了剪枝,计算时间得到了大大的提高!
以上是对剪枝及python装饰器的简单应用