-
2019-01-05 11:16:37
备忘录方法
动态规划算法的一个变形就是
备忘录方法
备忘录方法也用一个表格来保存已解决的子问题的答案.
在下次需要解决此问题时,只要简单地查看该子问题的解答,而不必重新计算.
但与动态规划不同:
-
备忘录方法的递归方式是自顶向下的,而动态规划算法则是自底向上递归的。
-
备忘录方法的控制结构与直接递归方法的控制结构相同
区别在于备忘录方法为每个解过的子问题建立了备忘录以备需要时查看,避免了相同子问题的重复求解
注意:
备忘录方法为每个子问题建立了一个记录项,初始化时,该记录项存入一个特殊的值,表示该子问题尚未求解
在求解过程中,对每个待求的子问题,首先查看相应的记录项。若记录项中存储的是初始化时存入的特殊值,则表示该子问题是第一次遇到,则此时计算出该子问题的解,并保存在相应的记录项中。若记录项中存储的已不是初始化时存入的特殊值,则表示该问题已被计算过,其相应的记录项中存储的是该子问题的解答。此时,只要从记录项中取出该子问题的解答即可。
LeetCode 135. Candy
Hard
/* There are N children standing in a line. Each child is assigned a rating value. N个小孩站在一条线上,每个小孩有一个rating value You are giving candies to these children subjected to the following requirements: 按下面的规则给糖 Each child must have at least one candy. 每个小孩至少有一个糖!!! Children with a higher rating get more candies than their neighbors. 有着高rate的小孩比它隔壁的小孩糖要多 What is the minimum candies you must give? Input: [1,0,2] Output: 5 Explanation: You can allocate to the first, second and third child with 2, 1, 2 candies respectively. */ // 递归的方法,备忘录法?O(N)时间,O(N)空间 class Solution { public: int helper(vector<int>& ratings, vector<int>& res,int index) { // 若没有求解,那么求解 if (res[index] == 0) { res[index] = 1;// if (index > 0 && ratings[index] > ratings[index - 1]) { // 如果它比左边大 res[index] = max(res[index], helper(ratings, res, index - 1)+1); } // 如果它比右边大 res[index] = max(res[index], helper(ratings, res, index + 1)+1); } return res[index]; } else { return res[index]; } } int candy(vector<int>& ratings) { int sz = ratings.size(); vector<int> res(sz); // 备忘录用于记录糖果数量,初始值为0,表示未求解 int sum = 0; for (int i = 0; i < sz; i++) { sum += helper(ratings, res, i); } return sum; } };
更多相关内容 -
-
备忘录方法
2021-03-24 21:22:47因此,备忘录方法的控制结构与直接递归方法的控制结构相同,区别在于备忘录方法为每个解过的子问题建立了备忘录以备需要时查看,避免了相同子问题的重复求解。 UML如下: 具体代码实现: 成绩单: public class ...定义:
备忘录方法也用一个表格来保存已解决的子问题的答案,在下次需要解决此问题时,只要简单地查看该子问题的解答,而不必重新计算。与动态规划算法不同的是,备忘录方法的递归方式是自顶向下的,而动态规划算法则是自底向上递归的。因此,备忘录方法的控制结构与直接递归方法的控制结构相同,区别在于备忘录方法为每个解过的子问题建立了备忘录以备需要时查看,避免了相同子问题的重复求解。
UML如下:
具体代码实现:
成绩单:
public class Originator { private String state; //成绩 public void setState(String state) { this.state = state; } public String getState() { return state; } public Memento Create() { //创造备忘录 return new Memento(state); } public void SetMemento(Memento memento) { //还原 this.state=memento.getState(); } public void show() { System.out.println("当前分数"+state); } }
备忘录:
public class Memento { public String state; public Memento(String state) { this.state=state; } public String getState() { System.out.println("正在还原"); return state; } }
管理者:
public class Administration { private Memento memento; //备忘录 public void setMemento(Originator originator) { this.memento = originator.Create(); } public Memento getMemento() { return memento; } }
主方法:
public class Main { public static void main(String[] args) { Originator originator=new Originator(); originator.setState("111"); originator.show(); Administration a=new Administration(); a.setMemento(originator);//设置备忘录 originator.setState("321");; originator.show(); originator.SetMemento(a.getMemento());//还原数据 originator.show(); } }
-
动态规划与备忘录方法的区别(矩阵连乘问题)
2021-03-24 09:31:03动态规划与备忘录方法的区别 动态规划算法的基本要素: 1 最优子结构性质 当问题的最优解包含了其子问题的最优解时,称该问题具有最优子结构性质。 2 重叠子问题性质 动态规划算法对每个问题只解一次,将其解保存在...动态规划与备忘录方法的区别(矩阵连乘问题)
动态规划算法的基本要素:
1 最优子结构性质
当问题的最优解包含了其子问题的最优解时,称该问题具有最优子结构性质。
2 重叠子问题性质
动态规划算法对每个问题只解一次,将其解保存在一个表格中,当再次需要解此问题时,用常数时间查看一下结果。因此,用动态规划算法通常只需要多项式时间。
备忘录方法:
•用一个表格来保存已解决的子问题的答案,用的时候查表即可。
•采用的递归方式是自顶向下。
•控制结构与直接递归相同,区别在于备忘录方式为每个解过的子问题建立备忘录。
•初始化为每个子问题的记录存入一个特殊的值,表示并未求解。在求解过程中,查看相应记录如果是特殊值,表示未求解,否则只要取出该子问题的解答即可。
备忘录方法与动态规划和递归的区别:
1、动态规划是自低向上 ,备忘录方法是自顶向下,递归是自顶向下
2、动态规划每个子问题都要解一次,但不会求解重复子问题;备忘录方法只解哪些确实需要解的子问题;递归方法每个子问题都要解一次,包括重复子问题• 。
矩阵连乘问题基本实现//备忘录方法 //建立备忘录 public static int memMatrixChain(int n) { for(int i=1;i<=n;i++) for(int j=i;j<=n;j++) m[i][j]=0;//备忘录先初始化都为0 return lookupChain(1,n); } //递归求解问题并先查表 public static int lookupChain(int i,int j) { if(m[i][j]>0) return m[i][j];//先查表,如果对应值不为0说明求解过,直接拿来用 if(i==j) return 0; int u=lookupChain(i+1,j)+p[i-1]*p[i]*p[j]; s[i][j]=i; for(int k=i+1;k<j;k++) { int t=lookupChain(i,k)+lookupChain(k+1,j)+p[i-1]*p[k]*p[j]; if(t<u) { u=t; s[i][j]=k; } } m[i][j]=u;//更新备忘录 return u; }
//动态规划 public static String matrixChain(int p[],int [][]m,int [][]n) { int n = p.length - 1; //为p的实际最大下标 for (int i = 1; i <= n; i++) { m[i][i] = 0; } for (int r = 2; r <= n; r++) // r为当前计算的链长(子问题规模) { for (int i = 1; i <= n - r + 1; i++)// n-r+1为最后一个r链的前边界 { int j = i + r - 1;// 计算前边界为r,链长为r的链的后边界 m[i][j] = m[i + 1][j] + p[i - 1] * p[i] * p[j];// 将链ij划分为A(i) *( A[i+1:j] ) s[i][j] = i; for (int k = i + 1; k < j; k++) { // 将链ij划分为( A[i:k] )* (A[k+1:j]) int t = m[i][k] + m[k + 1][j] + p[i - 1] * p[k] * p[j]; if (t < m[i][j]) { m[i][j] = t; s[i][j] = k; } } } }
-
备忘录方法之矩阵连乘积问题
2018-05-15 13:09:00在之前的文章中,我们学习了如何用动态规划算法实现矩阵的连乘积问题,由于矩阵连乘积...这样就可以得到一个基于递归算法的高效方法,即备忘录方法。备忘录方法的控制结构与直接递归方法的控制结构相同,区别在于备...在之前的文章中,我们学习了如何用动态规划算法实现矩阵的连乘积问题,由于矩阵连乘积问题具有子问题重叠性,所以采用递归算法求解时有些子问题会被反复计算多次,从而导致效率低下。如果在递归算法中引入二维数组 m[i][j] ,求解子问题后将解储存到 m[i][j] 中,下次可以直接读取使用。这样就可以得到一个基于递归算法的高效方法,即备忘录方法。备忘录方法的控制结构与直接递归方法的控制结构相同,区别在于备忘录方法为每个解过的子问题建立了备忘录以备需要时查看,避免了相同子问题的重复求解,需要注意的是,备忘录方法是动态规划算法的变形。
接下来我们用代码实现一下:
//用备忘录方法解决矩阵连乘积问题 #include<stdio.h> #define MAX_SIZE 100 int LookupChain(int i, int j, int p[MAX_SIZE], int m[MAX_SIZE][MAX_SIZE], int s[MAX_SIZE][MAX_SIZE]); int MemoizedMatrixChain(int n, int m[MAX_SIZE][MAX_SIZE], int s[MAX_SIZE][MAX_SIZE]); int MemoizedMatrixChain(int n, int p[MAX_SIZE], int m[MAX_SIZE][MAX_SIZE], int s[MAX_SIZE][MAX_SIZE]) { int i,j; //将最少数乘次数矩阵全部初始化为0 for(i = 1; i <= n; i++) { for(j = 1; j <= n; j++) { m[i][j] = 0; } } return LookupChain(1,n,p,m,s); } int LookupChain(int i, int j, int p[MAX_SIZE], int m[MAX_SIZE][MAX_SIZE], int s[MAX_SIZE][MAX_SIZE]) { if ( m[ i ][ j ] > 0 ) return m[ i ][ j ]; //因为m[i][j]的值位于上三角区域,当i=j时为单一矩阵,无需计算,直接返回0 if ( i == j ) return 0; //令k = i,即(i,k)~(k+1,j) 用于计算最小k值 int u = LookupChain( i, i ,p, m, s ) + LookupChain( i + 1, j, p, m, s ) + p[ i - 1 ] * p[ i ] * p[ j ]; s[ i ][ j ] = i; //该部分依次断开k=(i+1)~(j-1),求出s和m for ( int k = i + 1; k < j; k++ ) { int t = LookupChain( i, k ,p, m, s) + LookupChain( k + 1, j ,p, m, s) + p[ i - 1 ] * p[ k ] * p[ j ]; if ( t < u ) { u = t; s[ i ][ j ] = k; } } m[ i ][ j ] = u; return u; }
int main() { int p[MAX_SIZE];//矩阵连乘积A1A2...An中矩阵的位数一维数组,其中Ai的维数为Pi-1*Pi,i=1,2,..,n int n;//矩阵个数 int m[MAX_SIZE][MAX_SIZE];//最少数乘次数 int s[MAX_SIZE][MAX_SIZE];//A[i,j]的 最佳断开位置 int i; printf("请输入矩阵个数:\n"); scanf("%d",&n); printf("请输入矩阵的维度,如现在有一个10*20,20*30的矩阵,那么P0=10,P1=20,P2=30\n"); for(i = 0; i <= n; i++) { scanf("%d",&p[i]); } int minMuNum = MemoizedMatrixChain( n, p, m, s ); //最少数乘次数 printf("%d\n",minMuNum); }
这里我们需要注意一点,备忘录方法自顶向下计算,而动态规划算法是由对角线向右上角计算的。
运行结果如下:
-
备忘录方法与动态规划比较
2019-10-03 09:21:31动态规划算法的基本要素:1 最优子结构性质当问题的最优解包含了其子问题的最优解时,称该问题具有最...备忘录方法:•用一个表格来保存已解决的子问题的答案,用的时候查表即可。•采用的递归方式是自顶向下。•... -
最长公共子串LCS问题(动态规划及备忘录方法)
2018-10-11 11:48:58动态规划从下到上积累能量,中间值全部记录以方便后期计算时调用,但有些时候很多记录的值用不到,这个时候备忘录方法则更好,可以减少记录的值,其特点是自上到下,记录少部分值。以LCS最长公共子串问题威力,分别... -
算法作业-Ackermann函数-备忘录方法
2018-06-03 14:51:58Ackermann函数定义如下:1,请采用备忘录方法设计一个求解该函数的递归算法。2,请用动态规划方法设计一个非递归求解算法,该算法由两个嵌套循环组成,只能使用O(m)内的空间。解法一:备忘录方法使用一个二维数组A[m]... -
用动态规划算法的变形方法——备忘录方法,解决0-1背包问题
2016-05-04 10:59:20使用备忘录方法解决0-1背包问题: 1.跟直接递归很相似,该算法能将递归遇到的子问题的解保存在一个表中,以便下一个递归遇到同样的子问题时快速求解。 2.为了区分一个子问题是否已经求解,可以通过查表的方式来... -
动态规划&备忘录方法&递归方法
2015-10-29 21:08:39动态规划的基本思想是,将原问题拆分为若干子问题,自底向上的求解...备忘录方法,采用的也是自顶向下的思想,但是该方法维护了一个记录子问题解的表,虽然填表动作的控制结构更像递归方法,但是的确避免了子问题的重复 -
矩阵连乘积动态规划和备忘录方法Java实现
2015-05-11 21:51:04矩阵连乘积动态规划和备忘录方法Java实现,使用了两种算法实现,并且使用了改进了动态规划算法的备忘录方法以自顶向下的方法实现 -
动态规划-3.1.3矩阵连乘问题之备忘录方法(自顶向下)
2017-11-26 21:58:59备忘录方法为每个子问题建立一个记录项,初始化时,该记录项存入一个特殊值,表示该子问题尚未解决。在求解过程中,对每个待求子问题,首先查看其相应的记录项。有变化则不算,无则算。 代码如下:public class ... -
矩阵连乘问题(动态规划算法+备忘录方法)
2018-04-02 23:30:24备忘录方法 #include using namespace std ; int m[ 7 ][ 7 ],s[ 7 ][ 7 ]; int p[]={ 30 , 35 , 15 , 5 , 10 , 20 , 25 }; const int N= 6 ; int Lookupchain( int i, int j) { if (m... -
vue.js实现备忘录功能的方法
2021-01-19 19:12:29这个vue实现备忘录的功能demo是K在github上找到的,K觉得这是一个用来对vue.js入门的一个非常简单的demo,所以拿在这里共享一下。 (尊重他人劳动成果,从小事做起~ demo原github地址:https://github.com/vuejs/vue... -
vue实现日历备忘录功能
2020-10-16 18:57:07主要为大家详细介绍了vue实现日历备忘录功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 -
Android编程设计模式之备忘录模式详解
2020-08-28 10:45:20主要介绍了Android编程设计模式之备忘录模式,结合实例形式详细分析了Android备忘录模式的概念、原理、应用场景、用法及相关操作注意事项,需要的朋友可以参考下 -
算法导论15.3 备忘录方法
2017-03-28 22:47:03备忘录使动态规划的一种变形,此处用备忘录解决前面的矩阵链乘次数最少问题. 由之前的代码修改而来见该页 动态规划函数matrix_chain_order() 改为备忘录函数memoized_matrix_chain()和lookup_chain()#include #... -
矩阵连乘的动态规划算法(包括递归的备忘录方法)
2015-01-08 14:14:06//矩阵连乘的动态规划算法 #include using namespace std; long MaxtrixChain1(int n); long MaxtrixChain1(int i, int j); int const MAX = 1000; long subMatrixChain[MAX][MAX]; int bestK[MAX][MAX];...in -
【算法】备忘录法(记忆化搜索)
2020-11-11 22:18:52备忘录法的控制与直接使用递归方法的控制结构相同。 备忘录法又称记忆化搜索,自顶向下的方式解决问题。 备忘录法的实现 避免子问题重复被求解,我们可以定义一个数组,每次要计算一个子问题时,首先从数组中查询... -
生活不易,在忙也要花一分钟时间搞清分治、动态规划和备忘录的区别与联系
2020-12-14 11:01:48分治,动态规划,备忘录搞不清,遇到问题不知道应该用什么样的方法合适? 分治:分治算法对问题进行分解时所遵循的原则是将待求解问题分解为若干个规模较小、相互独立且与原问题相同的子问题(不包含公共的子问题... -
备忘录C语言(整理).pptx
2020-10-22 00:50:34计算机与信息工程系 高级语言程序设计课程设计报告;11;22;计算机与信息工程系 高级语言程序设计课程设计报告;44;计算机与信息工程系 高级语言程序设计课程设计报告 3 设计过程或程序代码;66;77;... -
【动态规划】矩阵连乘问题 备忘录方法:自顶向下递归
2013-03-06 08:31:20参考王晓东《计算机算法设计与分析》(第3版)动态规划章节中的内容 -
大话设计模式之爱你一万年:第十七章 行为模式:备忘录模式:和女朋友的重要节日不能忘...备忘录方法之记事本
2020-12-22 15:08:58一、备忘录方法模式之记事本 1.1 类图 1.2 编码 1.2.1 Memento: 备忘录角色 创建一个备忘录角色 - 备忘录Memento: package com.kfit.memento; /** * 创建一个备忘录角色 - 备忘录 * * @author 悟纤「...