首页 > 其他分享 >最长的递增子序列--动态规划、递归

最长的递增子序列--动态规划、递归

时间:2024-11-10 19:17:11浏览次数:3  
标签:递归 nums -- 递增 get int 序列

问题简述

对于一个数组,计算其中最长的递增子序列的长度,并输出。

主要思路如下:

代码中提供了三种不同的实现方法:纯递归、递归+动态规划(记忆化),以及纯动态规划(迭代)。下面是每种方法的主要思路:

1. 纯递归实现(dp方法)

这个方法尝试通过递归找到以每个元素结尾的最长递增子序列的长度。对于每个元素,它会比较后续所有元素,如果找到比当前元素大的元素,就增加计数。但是,这个方法有几个问题:

  • 它没有正确地返回递归调用的结果,导致递归的结果丢失。
  • 它没有正确地利用递归的性质来避免重复计算。

2. 递归+动态规划(记忆化)实现(dp2方法)

这个方法是对第一种方法的优化,它使用一个数组get来存储每个位置的最长递增子序列的长度,从而避免重复计算。主要思路如下:

  • 使用一个数组get来存储每个位置的最长递增子序列的长度。
  • 在递归之前,先检查get[j]是否已经被计算过,如果是,则直接返回该值。
  • 如果get[j]没有被计算过,那么递归地计算以nums[j]为起点的最长递增子序列的长度,并存储在get[j]中。
  • 在所有递归调用结束后,遍历get数组找到最大值,即为整个数组的最长递增子序列的长度。

3. 动态规划(迭代)实现(dp3方法)

这个方法使用迭代而不是递归来计算最长递增子序列的长度。主要思路如下:

  • 创建一个数组get,用于存储每个位置的最长递增子序列的长度。
  • 从数组的末尾开始向前遍历,对于每个元素,检查其后面所有元素是否比当前元素大,如果是,则更新get[i]的值。
  • 在遍历结束后,遍历get数组找到最大值,即为整个数组的最长递增子序列的长度。
package Dp;
/*
* 实现一个最长的递增子序列的计算,递归实现,递归+动态规划实现,动态规划实现
* */


public class LongestLCR {
    //递归的实现
    public static int dp(int [] nums,int j,int max){
        //递归的出口
        if(j == nums.length - 1){
            return 1;
        }

        int count = 1;//记录个数
        int pre = nums[j];

        for(int i = j ; i < nums.length; i++){
            if(nums[i] >  pre){
                count ++;
                pre = nums[i];
            }
        }

        max = Math.max(max,count);
        dp(nums,j + 1, max);

        //最终的返回值
        return max;
    }


    //递归形式的动态规划,进行一次优化
    public static int dp2(int[] nums, int j ,int[] get){
        //首先判断该处的最大长度是否已经进行存储
        if(get[j] != 0){
            return get[j];
        }

        //递归的出口
        if(j == nums.length - 1){
            return 1;
        }

        //还是进行递归,不同的是,所有j开始的结果都记录在get数组中,减少了相同的计算
        int maxlen = 1;
        for(int i = j + 1; i < nums.length; i++){
            if(nums[i] > nums[j]){
                maxlen  = Math.max(maxlen , dp2(nums,i,get) + 1);
            }
        }
        get[j] = maxlen;

        int result = 0;
        for (int i = 0; i < get.length; i++) {
            if(get[i] > result){
                result = get[i];
            }
        }

        return result;
    }

    //使用动态规划,但是使用迭代,不再使用递归
    public static int dp3(int[] nums){
        int result = 0;
        int[] get = new int[nums.length];

        //从尾部进行遍历,并记录每一个开始位置的结果
        for (int i = nums.length - 1; i >= 0 ; i--) {
            //记录每一个位置的结果
            get[i] = 1;
            //进行每一个位置的计算
            for(int j = i + 1; j < nums.length ; j ++){
                if(nums[j] > nums[i]){
                    get[i] = Math.max(get[i],get[j] + 1);
                }
            }
        }

        for (int j : get) {
            if (result < j) {
                result = j;
            }
        }
        return result;
    }


    public static void main(String[] args) {
        int[] array = new int[]{1, 4, 3, 2,5};
        System.out.println(
                "第一种方式的结果是:" + dp(array,0,0)
        );

        System.out.println(
                "第二种方式的结果是:" + dp2(array,0,new int[array.length])
        );

        System.out.println(
                "第三种方式的结果是:" + dp3(array)
        );
    }
}

总结

这三种方法都是用来解决最长递增子序列问题,但是它们的效率和实现方式不同。第一种方法效率较低,因为它没有避免重复计算,时间复杂度是指数级,一旦数据量增多,太慢了。第二种方法通过记忆化减少了重复计算,计算快了很多倍。第三种方法则是最常用的动态规划方法,它避免了递归调用的开销,通常也是效率最高的,这里只是输出了最长的递增子序列的长度,感兴趣的uu们可以思考下怎么输出对应的最长的递增字符串,假使只有一个最长递增子序列。

标签:递归,nums,--,递增,get,int,序列
From: https://blog.csdn.net/yf3241610146/article/details/143608143

相关文章

  • 如果你搞不懂排序,看这篇文章就对了,初学者也看得懂,其三:进阶插入排序——希尔排序
    目录一.希尔排序1.1希尔排序的原理1.2希尔排序的代码思路1.3希尔排序的代码实现1.1希尔排序的原理希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重......
  • Nuxt.js 应用中的 schema:extend事件钩子详解
    title:Nuxt.js应用中的schema:extend事件钩子详解date:2024/11/10updated:2024/11/10author:cmdragonexcerpt:schema:extend钩子使开发者能够扩展默认数据模式,为特定业务需求添加自定义字段和验证。categories:前端开发tags:Nuxt钩子数据扩展自定......
  • Java基础——常用API
    API(应用程序接口):java帮我们写好的一些程序,如类、方法等1.String1.1.创建String对象并封装字符串//1.直接用双引号得到字符串对象,封装字符串数据Stringname="xiaoming";System.out.println(name);//xiaoming//2.使用newString创建对象,并调用构造器来初始化......
  • Nuxt.js 应用中的 listen 事件钩子详解
    title:Nuxt.js应用中的listen事件钩子详解date:2024/11/9updated:2024/11/9author:cmdragonexcerpt:它为开发者提供了一个自由的空间可以在开发服务器启动时插入自定义逻辑。通过合理利用这个钩子,开发者能够提升代码的可维护性和调试能力。注意处理性能、错......
  • 第 5 章:格式化输出-Claude应用开发教程
    更多教程,请访问:Claude开发应用教程设置运行以下设置单元以加载您的API密钥并建立get_completion辅助函数。!pipinstallanthropic#Importpython'sbuilt-inregularexpressionlibraryimportreimportanthropic#RetrievetheAPI_KEY&MODEL_NAMEvaria......
  • Nuxt.js 应用中的 prepare:types 事件钩子详解
    title:Nuxt.js应用中的prepare:types事件钩子详解date:2024/11/8updated:2024/11/8author:cmdragonexcerpt:prepare:types钩子为Nuxt.js开发者提供了灵活定制TypeScript配置和声明的能力。通过使用此钩子,开发者能够确保TypeScript配置和类型声明能够满......
  • 特朗普申请上百件商标,人物名称商标注意!
    特朗普从2005年至今在中国申请注册123件商标,名称有“特朗普”、“川普”、“唐纳德.特朗普”、"TRUMP"、“DONALDTRUMP”等,主要是中英文名称,涉及了多个类别,申请主体是位于纽约的“唐纳德特朗普商标经营有限责任公司”,用一个主体专门申请商标做品牌管理。在申请注册商标时,......
  • NVIDIA研究团队推出MM-Embed
      每周跟踪AI热点新闻动向和震撼发展想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领域的领跑者。点击订阅,与未来同行!订阅:https://......
  • 洛谷 P1321 单词覆盖还原
    一、题目描述我有一个长度为l的字符串,最开始时,这个字符串由 l 个句号(.)组成。我在这个字符串中,将多次把 boy 或者 girl 两单词,依次贴到这个字符串中。后贴上单词,会覆盖之前贴上的单词,或者覆盖句号。最终,每个单词至少有一个字符没有被覆盖。请问,一共贴有几个 boy ......
  • 20222324石国力 《网络与系统攻防技术》 实验四
    1.实验内容一、恶意代码文件类型标识、脱壳与字符串提取对提供的rada恶意代码样本,进行文件类型识别,脱壳与字符串提取,以获得rada恶意代码的编写作者,具体操作如下:(1)使用文件格式和类型识别工具,给出rada恶意代码样本的文件格式、运行平台和加壳工具;(2)使用超级巡警脱壳机等脱壳软件,......