在本系列的文章中已经写了二叉树(Binary Tree)深搜(DFS)与广搜(BFS)哈希表(Hash Table)等等,计划接下来要写的是动态规划(Dynamic Programming,DP),它算得上是最灵活的一种算法。回忆笔者学习动态规划的时候,最开始接触的是经典的 “01背包” 问题;不过现在想起来,以“01背包问题”作为初次接触的动态规划算法的问题_并不友好_;花费了不少时间才慢慢感悟到动态规划算法的核心思想。

先前的文章中涉及了不少搜索算法,在搜索算法上融入动态规划算法思想的 记忆化搜索(Memorize Search)不妨是一个不错的_承前启后_的选择。相对于 “01背包”类问题,记忆化搜索 对初学者 理解 动态规划 更友好,也能更好的感受到其魅力所在。

记忆化搜索,所谓 “记忆” 引用 Geeksforgeeks 网站上介绍记忆搜索原文中一句话就是 “to transform the results of a function into something to remember.” 把函数的结果存储下来作为 “记忆”。将“记忆”应用于搜索算法上,也就是搜索到有记录了函数结果的地方,其实就不需要再进行函数计算,直接返回 “记忆” 的结果即可。

记忆化搜索是一种自顶向下(Top-Down)分析的算法,文字描述过于悬浮于理论,保持本系列文风且用算法题来看下记忆化搜索算法具体的内容。

自顶向下(Top-Down)

LeetCode 329. 矩阵中的最长递增路径【困难】

给定一个 m x n 整数矩阵 matrix ,找出其中 最长递增路径 的长度。

对于每个单元格,你可以往上,下,左,右四个方向移动。 你 不能 在 对角线 方向上移动或移动到 边界外。(即不允许环绕)。

  • 直接顺着题意进行分析,找到 “最长递增路径” 直接用搜索遍历,把 matrix每个单元格的最长递增路径都计算下,返回其中最长的路径。不妨就假设下有一个 search的函数能够计算出 以当前单元格为起点的最长递增路径长度。遍历过程中 的最大长度 存储再 max 中,最后返回即可,代码如下:
// 假设中的函数
public int search(int[][] matrix,int x,int y){
int max;
return max;
} public int longestIncreasingPath(int[][] matrix) { int max = 0;
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[0].length; j++) {
//(i,j)格的最长递增路径长度
max = Math.max(max,search(matrix,i,j));
}
}
return max;
}
  • 问题开始关键点现在变成了 search 函数的实现;接着顺着题意分析,可以往上,下,左,右四个方向移动.首先考虑一个方向情况,只往上方向移动且可以往上移动(上方相邻的单元格大于当前单元格,递增),那么此时 当前单元格的最大路径长度就是 上方单元格的最大路径 + 1,其中1代表当前单元格。
public int search(int[][] matrix,int x,int y){

	int number = matrix[x][y],up = 1;

	// 保障可以往“上”移动, x-1 没有越边界( x > 0 )
// 且是 递增的 matrix[x-1][y] > number
if( x > 0 && matrix[x-1][y] > number ){ // 递归调用,同类子问题,(x-1,y)格的最长递增路径长度
up += search( matrix, x-1, y );
} return up;
}
  • 如此,扩展到 四个方向,最终当前单元格最大路径就是 四个方向中取最大的返回。
public int search(int[][] matrix,int x,int y){

        int number = matrix[x][y],up = 1,down =1,left=1,right=1;

        if(x>0 && matrix[x-1][y] > number){
up += search(matrix,x-1,y);
}
if(x+1<matrix.length && matrix[x+1][y] > number){
down += search(matrix,x+1,y);
}
if(y+1<matrix[0].length && matrix[x][y+1] > number){
right += search(matrix,x,y+1);
}
if(y>0 && matrix[x][y-1] > number){
left += search(matrix,x,y-1);
} return Math.max(Math.max(up,down),Math.max(right,left));
}
  • 实现到这里按照搜索思路的算法已经完成;不过会发现性能不高,分析过程会发现调用 search函数 时候,同样一格位置会计算多次。此时联系想想先前提到的 “记忆” ,把函数的结果存储下来作为 “记忆”,也就是用 一个二维数组 cahce 缓存起来 已经计算过单元的结果。

    search 实现改为 (cache需要在 longestIncreasingPath 根据 matrx大小 new下,这里略) ,代码如下:

public int[][] cache = null;

public int search(int[][] matrix,int x,int y){

        if(0 != cache[x][y])
return cache[x][y]; int number = matrix[x][y],up = 1,down =1,left=1,right=1;
if(x>0 && matrix[x-1][y] > number){
up += search(matrix,x-1,y);
}
if(x+1<matrix.length && matrix[x+1][y] > number){
down += search(matrix,x+1,y);
}
if(y+1<matrix[0].length && matrix[x][y+1] > number){
right += search(matrix,x,y+1);
}
if(y>0 && matrix[x][y-1] > number){
left += search(matrix,x,y-1);
}
// 存储 “记忆”
cache[x][y] = Math.max(Math.max(up,down),Math.max(right,left));
return cache[x][y];
}
  • 到此,已经按照记忆化搜索算法思路完成了问题的解决。

回顾下记忆化搜索解题过程,我们是从算法问题出发 -> 分析需要完成的计算(子问题)-> 进一步进行解决。这其实就是 自顶向下(Top-Down)的思考方式。

记忆化搜索 与 动态规划

再来看"记忆",cache[x][y] 所记录的是 x,y 这个单元格已经计算过的 最大路径长度当前单元格 的最大路径长度使用上、下、左、右四个方向上的单元格 最大路径长度 来进行计算 ,使用"记忆" 其实就是在使用子问题的最优解。


current_max = Max( up+1, down+1, left+1, right+1 )

另外一个角度描述,规划决策 当前单元格的最大路径 是根据 (上、下、左、右)相邻四个方向上的单元格最大路径 进行的计算。相邻四个方向上的最大路径(子问题最优解) 并非一开始静态写入下来,而是在程序运行过程中至少计算一次存储下来,可看作 动态的计算。根据动态计算子问题最优结果来进行规划决策当前最优结果,也就是所谓 动态规划(Dynamic Programming)的字面意思。

可以多体会下: 解决最优化问题,根据子问题的最优结果 规划决策 -> 当前问题最优结果 -> 进而求解最初问题。

所以有一种说法就是:记忆化搜索 是 动态规划 自顶向下(Top-Down)分析的一种实现形式,通常用递归来实现。

最后总结本文

  1. 本系列文章中写此篇 承前启后的思考,记忆化搜索 的基本概念;
  2. 通过一道题演示 自顶向下(Top-Down)的分析,实际应用记忆化搜索解决 具体算法问题;
  3. 解读 记忆化搜索 与 动态规划 的关系,以及动态规划一些概念;

下一篇咱们再一起继续解读 动态规划(Dynamic Programming) ,欢迎关注 Java研究者专栏、博客、公众号等

数据结构与算法 | 记忆化搜索(Memorize Search)的更多相关文章

  1. hdoj1078(介绍记忆化搜索及其模板)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1078 思路: 这是一道典型的记忆化搜索模板题. 先介绍记忆化搜索,本质是搜索+DP. 一般说来,动态规 ...

  2. 数位dp/记忆化搜索

    一.引例 #1033 : 交错和 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个数 x,设它十进制展从高位到低位上的数位依次是 a0, a1, ..., an  ...

  3. ZOJ3795 Grouping(强连通分量+缩点+记忆化搜索)

    题目给一张有向图,要把点分组,问最少要几个组使得同组内的任意两点不连通. 首先考虑找出强连通分量缩点后形成DAG,强连通分量内的点肯定各自一组,两个强连通分量的拓扑序能确定的也得各自一组. 能在同一组 ...

  4. 多校5 1001 HDU5781 ATM Mechine 记忆化搜索+概率

    // 多校5 1001 HDU5781 ATM Mechine // http://acm.hdu.edu.cn/search.php?field=problem&key=2016+Multi ...

  5. poj--1579--(DFS+记忆化搜索之经典)

    记忆化搜索   记忆化搜索:算法上依然是搜索的流程,但是搜索到的一些解用 动态规划的那种思想和模式作一些保存. 一般说来,动态规划总要遍历所有的状态,而搜索可以排除一些无效状态. 更重要的是搜索还可以 ...

  6. UVA1351-----String Compression-----区间DP(记忆化搜索实现)

    本文出自:http://blog.csdn.net/dr5459 题目地址: http://uva.onlinejudge.org/index.php?option=com_onlinejudge&a ...

  7. zoj 1107 FatMouse and Cheese(记忆化搜索)

    题目链接:点击链接 题目大意:老鼠从(0,0)出发,每次在同一个方向上最多前进k步,且每次到达的位置上的数字都要比上一个位置上的数字大,求老鼠经过的位置上的数字的和的最大值 #include<s ...

  8. vj1011:记忆化搜索

    vj1011:记忆化搜索 这题就是很简单的记忆化搜索即可,和经典题目滑雪简直一模一样 对于记忆化搜索,我也是暑假看了ccy大神的题解才有所领悟的 其实也就是DFS+mark 主要的部分 int sea ...

  9. 【noip 2009】 乌龟棋 记忆化搜索&动规

    题目背景 小明过生日的时候,爸爸送给他一副乌龟棋当作礼物. 题目描述 乌龟棋的棋盘是一行N个格子,每个格子上一个分数(非负整数).棋盘第1格是唯一的起点,第N格是终点,游戏要求玩家控制一个乌龟棋子从起 ...

  10. 2017广东工业大学程序设计竞赛决赛 题解&源码(A,数学解方程,B,贪心博弈,C,递归,D,水,E,贪心,面试题,F,贪心,枚举,LCA,G,dp,记忆化搜索,H,思维题)

    心得: 这比赛真的是不要不要的,pending了一下午,也不知道对错,直接做过去就是了,也没有管太多! Problem A: 两只老虎 Description 来,我们先来放松下,听听儿歌,一起“唱” ...

随机推荐

  1. 我真的想知道,AI编译器中的IR是什么?

    随着深度学习的不断发展,AI 模型结构在快速演化,底层计算硬件技术更是层出不穷,对于广大开发者来说不仅要考虑如何在复杂多变的场景下有效的将算力发挥出来,还要应对 AI 框架的持续迭代. AI 编译器就 ...

  2. Django CSRF cookie not set.

    错误原因 由于django框架的settings.py配置了中间件,为了防止跨站请求伪造,form表单POST方式会导致出现报错 解决办法: 将'django.middleware.csrf.Csrf ...

  3. UE源码分析:Slate 类鼠标输入处理

    序言 UE4.25版本 本章看一下UE的 "类鼠标"输入处理(其实就是鼠标和触摸的输入,我也没找到专门的术语来代指,英文UE用的是PointerXXX),主要是按下.移动.抬起等相 ...

  4. 第一个程序PingPong

    功能需求 如图所示,开启两个ping类型的服务ping1和ping2,ping1给ping2发消息,ping2收到回应ping1,ping1收到再回应ping2,不断循环. 服务模块 Skynet提供 ...

  5. Git-更换服务器问题

    一.Permission denied (publickey) git指令出现Permission denied (publickey),是ssh key过期的问题,需要对ssh key进行更新,所有 ...

  6. API数据接口的应用步骤

    API(Application Programming Interface)是现代软件应用程序开发中的一项重要技术,它允许不同的应用程序之间进行通信和数据交换.API接口通过提供统一的访问点,使得应用 ...

  7. 【项目源码】基于JavaEE的健康管理系统

    随着网络技术的不断发展,网站的开发与运用变得更加广泛.这次采用java语言SSH框架(Spring,Struts,Hibernate)设计并实现了面向特定群体的健康管理平台.该网站主要有教师饮食管理. ...

  8. shell、python时间函数小结

    有时需要写一些定时任务脚本,简单总结一下,备忘. 1. 获取当前时间 python 在windows下精确到0.001秒,linux下时间精度为0.000001秒 >>> impor ...

  9. 线段树hdu-4027

    Smiling & Weeping   ---- 姑娘,倘若,我双手合十的愿望里有你呢 Problem Description A lot of battleships of evil are ...

  10. MindSpore简要性能分析

    技术背景 在之前的一篇博客中,我们介绍过MindInsight的安装与使用.不过在前面的文章中,我们主要介绍的是MindInsight与SummaryCollector的配合使用,更多的是用于对结果进 ...