动态规划的实现及关键点

217 阅读1分钟

动态规划定义

  • 将一个复杂得问题 分解为简单得子问题
  • 分治+最优子结构
  • 动态规划和递归、分治, 没有本质得区别, 关键看有无最优得子结构
  • 共性 找到重复得子问题 本质就是寻找重复性
  • 差异性 动态规划有最优子结构, 中途可以提淘汰次优解

动态规划关键点

  • 1最优子结构
  • 2存储中间撞状态
  • 3递推公式(dp 方程)
    • Fib: opt[i] = opt[i-1] + opt[i-2]
    • 二维路径: opt[i,j] = opt[i+1][j] +opt[i][j+1]

例题1 斐波那契数列

递归解法 O(n^2) 递归不是最优解

def fib(n):
	if n <= 1:
		return n

	return fib(n-1) + fib(n-2)

可以添加缓存,例如lru cache 时间复杂度O(n)

memory = dict()

def fib(n):
    if n <= 1:
        return n

    if memory.setdefault(n, 0) == 0:
        memory[n] = fib(n - 1) + fib(n - 2)

    return memory[n]

自底向上 从最下面开始 循环不断累积结果,时间复杂度O(n)

def fib2(n):
    """
    自底向上得方法
    return
    """
    memory[0] = 0
    memory[1] = 1
    if n < 1:
        return memory[n]

    i = 0
    while i <= n:
        if memory.setdefault(n, 0) == 0:
            memory[i] = memory[i-1] + memory[i-2]
        i += 1

    return memory[n]

例题2 路径计数

思路: 当前点的走法总和 = 右边点的走法总和 + 下面点的走法总和

递归代码模板

# Python
def recursion(level, param1, param2, ...): 
    # recursion terminator 
    if level > MAX_LEVEL: 
	   process_result 
	   return 
    # process logic in current level 
    process(level, data...) 
    # drill down 
    self.recursion(level + 1, p1, ...) 
    # reverse the current level status if needed    

分治代码模板

# Python
def divide_conquer(problem, param1, param2, ...): 

  # recursion terminator 
  if problem is None: 
	print_result 
	return 

  # prepare data 
  data = prepare_data(problem) 
  subproblems = split_problem(problem, data) 

  # conquer subproblems 
  subresult1 = self.divide_conquer(subproblems[0], p1, ...) 
  subresult2 = self.divide_conquer(subproblems[1], p1, ...) 
  subresult3 = self.divide_conquer(subproblems[2], p1, ...) 
  …

  # process and generate the final result 
  result = process_result(subresult1, subresult2, subresult3, …)
	
  # revert the current level states