记忆化搜索题目练习

记忆化搜索

并不是所有递归都可以转化成记忆化搜索,记忆化搜索必须是出现完全重复的递归才可以,仅仅相似不可以转化成记忆化搜索

斐波那契数

题目解析:求第n个斐波那契数


java 复制代码
//递归
class Solution {
    public int fib(int n) {
        return dfs(n);
    }
    public int dfs(int n){
        if(n == 0 || n == 1){
            return n;
        }
        return dfs(n-1) + dfs(n-2);
    }
}
java 复制代码
//记忆化搜索
class Solution {
    int[] memory;
    public int fib(int n) {
        memory = new int[31];
        //初始化这个备忘录
        Arrays.fill(memory,-1);
        return dfs(n);
    }
    public int dfs(int n){
        //已经计算过,备忘录已经存过了,直接返回
        if(memory[n] != -1){
            return memory[n];
        }
        if(n == 0 || n == 1){
            memory[n] = n;//将结果对应放入备忘录中
            return n;
        }
        //返回之前将结果放入备忘录
        memory[n] = dfs(n-1) + dfs(n-2);
        return memory[n];
    }
}
java 复制代码
//动态规划
class Solution {
    int[] dp = new int[31];//记忆化搜索
    public int fib(int n) {
        dp[0] = 0;
        dp[1] = 1;
        for(int i = 2;i <= n;i++){
            dp[i] = dp[i-1] + dp[i-2];
        }
        return dp[n];
    }
}

不同路径

题目解析 :从start位置到finish位置有多少路径可以走,每次只可以向下或向右走一步
解法一
直接递归 ,到第(m,n)位置等于 到第(m-1,n) + 到第(m,n-1),

递归截止 m==0 || n == 0越界了 ,m = 1 && n=1 起始位置

dfs(m,n) = dfs(m-1,n) + dfs(m,n-1),但是时间超时了
解法二:记忆化搜索

这里有重复计算一个位置的问题,可以使用记忆化搜索

int[m+1][n+1] memo每个位置表示(1,1)到这个位置的路径和
解法三:动态规划

int[m+1][n+1] dp;先初始化dp[1][1] = 1,直接双重for循环遍历并且给数组对应值即可dp[i][j] = dp[i-1][j] + dp[i][j-1]


java 复制代码
//记忆化搜索
class Solution {
    public int uniquePaths(int m, int n) {
        int[][] memo = new int[m+1][n+1];
        return dfs(m,n,memo);
    }
    public int dfs(int m,int n,int[][] memo){
        //看是否存过
        if(memo[m][n] != 0){
            return memo[m][n];
        }
        if(m == 0 || n == 0){
            return 0;
        }
        if(m == 1 && n == 1){
            memo[m][n] = 1;
            return 1;
        }
        //更新meno
        memo[m][n] = dfs(m-1,n,memo) + dfs(m,n-1,memo);
        return memo[m][n];
    }
}
java 复制代码
//动态规划
class Solution {
    public int uniquePaths(int m, int n) {
        int[][] dp = new int[m+1][n+1];
        dp[1][1] = 1;
        for(int i = 1;i <= m;i++){
            for(int j = 1;j <= n;j++){
            //起始位置不需要进行初始化了
                if(i == 1 && j == 1){
                    continue;
                }
                dp[i][j] = dp[i-1][j] + dp[i][j-1];
            }
        }
        return dp[m][n];
    }
    
}

最长递增自序列

题目解析 :找出一个最长递增自序列,不一定是连续的,但相对顺序是从前向后
解法一:递归

以pos位置开始最长子序列 = 以pos+1位置开始 并且位置值大于 pos位置值开始最长子序列 + 1,但是时间超时
解法二:记忆化搜索

和递归一样,因为这里有重复操作,使用一个memo,下标对应从那个位置开始最长子序列,递归前先看memo中是否有值,返回结果前,更新对应memo值

解法三:动态规划

以pos位置开始最长子序列,依赖从pos+1 ~ n 位置开始最长子序列 ,直接其基础上+1即可,因此可以先从后向前将其最长子序列进行赋值,下标对应的下标就是从那个位置开始最长子序列


java 复制代码
class Solution {
    int n;
    int[] memo;
    public int lengthOfLIS(int[] nums) {
        n = nums.length;
        memo = new int[n];
        int ret = 0;
        for (int i = 0; i < n; i++) {
            ret = Math.max(ret, dfs(nums, i));
        }
        return ret;
    }

    public int dfs(int[] nums, int pos) {
        if(memo[pos] != 0){
            return memo[pos];
        }
        int tem = 1;
        for (int i = pos + 1; i < nums.length; i++) {
            if (nums[i] > nums[pos]) {
                tem = Math.max(tem,dfs(nums,i)+1);
            }
        }
        memo[pos] = tem;
        return memo[pos]; 
    }
}
java 复制代码
class Solution {
    public int lengthOfLIS(int[] nums) {
        int n = nums.length;
        int[] dp = new int[n];
        int ret = 0;
        Arrays.fill(dp,1);//先初始化为1

        //从后向前
        for(int i = n-1;i >= 0;i--){
            for(int j = i+1;j < n;j++){
                //从i+1位置开始后面,选那个数使其dp[i]最大
                if(nums[j] > nums[i]){
                    dp[i] = Math.max(dp[i],dp[j]+1);
                }
            }
            ret = Math.max(ret,dp[i]);
        }
        return ret;
    }
}

猜数字大小||

题目解析: 每次猜错数字都会扣除猜的数字金额,给了一个n,可以选1~n中任意数进行猜测,求出最小金额数可以满足无论猜1到n那个数金额都够
思想 :[1,n]中任意选一个数分为两部分,找出左部分最小金额点x,找出右边部分最小金额点y,Math.max(x,y)这样两边都满足,找出以所有起点中最小的金额数即可

记忆化搜索:可以使用一个二维数组,下标对应其区间,初始化为0


java 复制代码
//记忆化搜索
class Solution {
    int[][] memo;
    public int getMoneyAmount(int n) {
        memo = new int[n+1][n+1];
        return dfs(1,n);
    }
    public int dfs(int left,int right){
      
        //left == right此时只有一个值可以选,这个就是结果
        //left > right越界了已经
        if(left >= right){
            return 0;
        }
          
        if(memo[left][right] != 0){
            return memo[left][right];
        }

        int ret = Integer.MAX_VALUE;
        for(int head = left ; head <= right;head++){
            int x = dfs(left,head-1);
            int y = dfs(head+1,right);
            //x和y最大值,这样才可以无论选什么左右两边都可以猜出数字
            //但是要从所有结果中选出最小金额可
            ret = Math.min(Math.max(x,y)+head,ret);
        }
        memo[left][right] = ret;
        return memo[left][right];
    }
}

矩阵中的最长递增路径

题目解析 :找出最长递增路径,可以从任意位置作为起点

解法:记忆化搜索

找出以某个位置作为起点的最长路径,需要找其上下左右四个方向那个最长递增路径最长

ret = Math.max(ret,dfs(x,y) + 1)

返回以某个起点是最长路径长度

java 复制代码
class Solution {
    int m,n;
    int[] dx = {1,-1,0,0};
    int[] dy = {0,0,1,-1};
    int[][] memo;
    public int longestIncreasingPath(int[][] matrix) {
        m = matrix.length;
        n = matrix[0].length;
        memo = new int[m][n];
        int ret = 0;
        for(int i = 0;i < m;i++){
            for(int j = 0;j < n;j++){

                ret = Math.max(ret,dfs(matrix,i,j));
            }
        }
        return ret;
    }
    public int dfs(int[][] matrix,int i,int j){
        if(memo[i][j] != 0){
            return memo[i][j];
        }
        int ret = 1;
        for(int k = 0;k < 4;k++){
            int x = i + dx[k];
            int y = j + dy[k];

            if(x >= 0 && x < m && y >= 0 && y < n && matrix[x][y] > matrix[i][j]){
                ret = Math.max(ret,dfs(matrix,x,y)+1);
            }
        }
        memo[i][j] = ret;
        return memo[i][j];
    }
}
相关推荐
闻缺陷则喜何志丹1 小时前
【C++动态规划】B3734 [信息与未来 2017] 加强版密码锁|普及+
c++·算法·动态规划·洛谷
是娇娇公主~1 小时前
力扣——105. 从前序与中序遍历序列构造二叉树详解
算法·leetcode·哈希算法
承渊政道1 小时前
【贪心算法】(经典实战应用解析(三):K次取反后最⼤化的数组和、按⾝⾼排序、优势洗牌、最⻓回⽂串、增减字符串匹配)
数据结构·c++·学习·算法·贪心算法·线性回归·哈希算法
长谷深风1111 小时前
SpringBoot开发秘籍【个人八股】
java·spring boot·后端·spring·八股
凌波粒1 小时前
LeetCode--100.相同的树(二叉树)
算法·leetcode·职场和发展
alexwang2111 小时前
P16473 [GKS 2013 #B] Sudoku Checker题解
c++·算法·题解·洛谷
ch.ju1 小时前
Java Programming Chapter 4——Dynamic part
java·开发语言
无敌昊哥战神2 小时前
【机器学习扫盲】从预测 Score 到ACC、 Precision、Recall、ROC 曲线的白话全解
python·深度学习·算法·机器学习
隔窗听雨眠2 小时前
RPA + Java构建高并发智能抢票系统的完整实践
java·rpa·抢票·12306