记忆化搜索题目练习

记忆化搜索

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

斐波那契数

题目解析:求第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),但是时间超时了
解法二:记忆化搜索

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

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

intm+1n+1 dp;先初始化dp11 = 1,直接双重for循环遍历并且给数组对应值即可dpij = dpi-1j + dpij-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];
    }
}
相关推荐
一个儒雅随和的男子5 分钟前
限流算法详细剖析
java·服务器·算法
我是一颗柠檬8 分钟前
【Java项目技术亮点】分布式锁实现与优化:从Redisson到ZooKeeper,彻底搞懂分布式锁的底层原理
java·redis·分布式·中间件·java-zookeeper
ANnianStriver9 分钟前
PetLumina 04 — 管理后台 UI 全面升级
java·ui·ai编程
winlife_12 分钟前
全程用 AI 做一款商业级手游 · EP9 收尾与复盘:做到了哪,没做到哪,边界在哪
java·开发语言·人工智能·unity·ai编程·游戏开发·mcp
云恒要逆袭17 分钟前
Hello World背后的秘密:Java程序是这样运行的
java·后端·程序员
JAVA96519 分钟前
JAVA面试-并发篇 09-LockSupport 和 waitnotify 的区别
java·开发语言·面试
蝎子莱莱爱打怪21 分钟前
XZLL-IM干货系列 01|万字拆解分布式 IM 架构:7 个微服务 + 自研 Flutter SDK
java·后端·面试
程序员小羊!28 分钟前
07Java IO 流
java·开发语言
ZC跨境爬虫29 分钟前
跟着 MDN 学JavaScript day_10:数组——数据的有序集合
android·java·开发语言·前端·javascript
亦暖筑序33 分钟前
Java 8老系统旁路接入AI Gateway:不升级JDK也能用AI
java·spring boot·aigc·企业架构·ai gateway