【记忆化搜索】最长递增子序列

文章目录

题目链接:300. 最长递增子序列


题目解析

记忆化搜索 是一种通过记录已经遍历过的状态的信息,从而避免对同一状态重复遍历的搜索实现方式(是一种常见的动态规划实现方式)。

可以通过记忆化搜索来优化 DFS(剪枝)以提高算法效率。

本题给出一个整数数组 nums,我们需要找到其中最长严格递增子序列的长度并返回(子序列指的是数组中的元素按照删除或不删除且不改变其余元素顺序的序列)。

例如 [3, 6, 2, 7] 是数组 [0, 3, 1, 6, 2, 2, 7] 的子序列。

例1:nums = 10, 9, 2, 5, 3, 7, 101, 18

找出的最长递增子序列是:

  1. 2, 5, 7, 101
  2. 2, 3, 7, 101
  3. 2, 5, 7, 18
  4. 2, 3, 7, 18

以上四种情况均是例1的最长递增子序列,且长度都为 4,因此返回 4


DFS:深度优先搜索

算法原理

最简单的方式就是:遍历nums数组,将每个数逐个当作起点,找到以该数为起点的递增子序列的最大值

全局变量

为了递归方便,将 nums 改为全局变量,同时 n 为数组 nums 的长度。

java 复制代码
int[] nums;
int n;

dfs 函数

函数头

我们给 dfs 函数的任务是:找到以pos位置为起点的递增子序列的最大值 ,其中 pos 为函数的参数,表示下标位置,返回值为 int。

java 复制代码
int dfs (int pos);
函数体

dfs 函数的具体步骤是:从pos位置往后找比当前数字更大的数,然后获取它的 dfs 值(以该数为起点的最长子序列长度)并更新自己的用于记录长度的变量。

当遍历完 nums 数组,递归结束,返回结果即可。

代码实现

java 复制代码
class Solution {
    int[] nums;
    int n;

    public int lengthOfLIS(int[] givenNums) {
        // 初始化
        nums = givenNums;
        n = nums.length;
        int ret = 0; // 记录最长子序列

        // 遍历nums,以每个位置为起点找到所有递增子序列的最大值
        for (int i = 0; i < n; i++) {
            ret = Math.max(dfs(i), ret); // 更新结果
        }

        // 返回结果
        return ret;
    }

    // dfs任务:找到以pos位置为起点的递增子序列长度的最大值
    public int dfs (int pos) {
        int count = 0;
        for (int k = pos+1; k < n; k++) {
            if (nums[k] > nums[pos]) {
                count = Math.max(dfs(k), count);
            }
        }
        count++;
        // 返回结果
        return count;
    }
}

记忆化搜索

使用递归法会超时,因为整个递归的展开图是一棵多叉树,时间复杂度相当高。

例如,nums = 2, 5, 3, 7, 101, 18,画出的比分递归展开图:

可以发现有很多重复展开的过程,这是导致超时的最主要原因,我们可以想办法剪枝以提高效率。

算法原理

记忆化搜索的本质就是 "带着记忆递归搜索" ,而 记忆数组/备忘录 正是这类问题的关键。

记忆数组

本题针对 pos 进行记忆化处理,需要一个一维数组 当作记忆数组,值为 以pos位置为起始的最长递增子序列长度

  1. 在递归展开之前,先查看记忆数组/备忘录
  2. 在递归展开之后,先将得到的结果存入记忆数组/备忘录,再返回

代码实现

java 复制代码
class Solution {
    int[] nums;
    int n;
    int[] memo; // 记忆数组

    public int lengthOfLIS(int[] givenNums) {
        // 初始化
        nums = givenNums;
        n = nums.length;
        memo = new int[n];
        int ret = 0; // 记录最长子序列

        // 遍历nums,以每个位置为起点找到所有递增子序列的最大值
        for (int i = 0; i < n; i++) {
            ret = Math.max(dfs(i), ret); // 更新结果
        }

        // 返回结果
        return ret;
    }

    // dfs任务:找到以pos位置为起点的递增子序列长度的最大值
    public int dfs (int pos) {
        // 递归展开之前,先查看记忆数组
        if (memo[pos] != 0) {
            return memo[pos];
        }

        int count = 0;
        for (int k = pos+1; k < n; k++) {
            if (nums[k] > nums[pos]) {
                count = Math.max(dfs(k), count);
            }
        }
        count++;
        
        // 递归展开之后,先将结果存入记忆数组再返回
        memo[pos] = count;
        return count;
    }
}

文章到这里就告一段落啦,若有错误请尽管指出~

相关推荐
东方护航数据恢复(深圳)3 小时前
本地小算力设备数据恢复经典案例实操全解_东方护航数据恢复深圳店
大数据·服务器·算法·ai·gpu算力
杨杨杨大侠3 小时前
知识库已经有了,Java 程序员还要做什么?Spring AI RAG 实战
java·openai·ai编程
伊信4 小时前
Spring AI 基础学习与应用
java·后端
Omics Pro4 小时前
上海AI Lab孙思琦×高张阳:虚拟细胞代码库智能体
数据库·人工智能·算法·机器学习·自然语言处理
Y幽谷客4 小时前
图像识别入门习题整理
算法
夜郎king4 小时前
基于 Java + Playwright 实现网站自动访问与数据采集(以腾讯云开发者社区为例)
java·playwright·网页数据获取
Anastasiozzzz4 小时前
重新定义 Agent 基建:Redis 在现代 AI 与智能体系统中的工程实践
java·人工智能·redis·ai
careathers4 小时前
【数据结构】队列
java·数据结构
步行cgn4 小时前
Spring 通过 factory-method 实例化 Bean 详解与常见错误排查
java·后端