首页 > 其他分享 >动态规划-1:穷举遍历->map缓存->取消递归

动态规划-1:穷举遍历->map缓存->取消递归

时间:2024-07-21 11:55:47浏览次数:14  
标签:tmp map arr 缓存 int length maxLen startIndex 穷举

import java.util.HashMap;
import java.util.Map;

public class DynamicProgrammingAlgorithm {

    public static void main(String[] args) {
        //比如 要求一个数组的最长递增子序列的长度
        //比如是[1,4,2,5,3],那么[1,2,5],或者[1,2,3]都是最长递增子序列,所以应该返回3
        //如何用算法实现,最简单的方法是暴力枚举
        int[] arr = {1,4,2,5,3};
        int largestAscendingSubArrLength = getLargestAscendingSubArrLength(arr);
        System.out.println(largestAscendingSubArrLength);

        int[] arr2 = {958,95,812,650,443,412,872,921,975,201,576,548,
                257,694,53,797,640,424,556,955,806,807,467,45,270,565,
                778,662,537,435,167,867,971,108,810,838,401,809,803,702,
                836,654,491,14,729,890,684,293,732,892,326,664,815,566,
                434,592,877,657,611,795,474,408,266,975,589,316,681,763,
                115,941,328,311,108,263,822,447,600,914,326,478,386,117,928,
                978,383,110,392,373,67,335,64,62,956,950,778,363,13,524,686,
                411,654,346,345,768,505,822,556,350,353,706,689,844,500,488,614,
                587,540,437,886,273,561,798,341,149,817,878,418,134,99,398,731};


        long start = System.currentTimeMillis();
        System.out.println(getLargestAscendingSubArrLength(arr2));
        System.out.println("用了"+(System.currentTimeMillis()-start)+ "毫秒");

        System.out.println("===================================");
        System.out.println(getSubArrLengthFromGivingStartAdvanced(arr));
        System.out.println(getSubArrLengthFromGivingStartAdvanced(arr2));
    }

    public static int getLargestAscendingSubArrLength(int[] arr){

        /**
         * key:表示从哪个索引index开始查找递增子序列
         * value:表示从索引key开始的最长递增子序列为value个
         */
        Map<Integer,Integer> map = new HashMap<>();

        //我从1开始,先找所有以1开头的子序列;然后找4;以此类推
        int large = 0;
        for (int i = 0; i < arr.length; i++) {
            int tmpLarge = getSubArrLengthFromGivingStart(arr, i);
            if (tmpLarge > large){
                large = tmpLarge;
            }
        }
        return large;
    }

    /**
     * 返回数组arr从startIndex开始的最长递增子序列的长度
     * @param arr
     * @param startIndex
     * @return
     * //比如是arr = [1,4,2,5,3] startIndex=0
     */
    public static int getSubArrLengthFromGivingStart(int[] arr,int startIndex){
        int maxLen = 1;

        if (startIndex < arr.length-1){
            for (int i = startIndex + 1; i < arr.length; i++) {
                if (arr[i] > arr[startIndex]){
                    int tmp = getSubArrLengthFromGivingStart(arr,i)+1;
                    maxLen = tmp>maxLen?tmp:maxLen;
                }
            }
        }
        //如果传入startIndex = arr.length-1,也即从最后一个元素开始找,显然是1
        return maxLen;
    }

    /**
     * 上述getSubArrLengthFromGivingStart最大的问题在于存在大量的重复计算
     * 比如startIndex=3,也即从元素5开始的子序列,我们计算1,5,3时计算过,计算2,5,3时也要计算
     * 优化方案,把计算过的值存起来,直接取,避免重复计算
     * @param arr
     * @param startIndex
     * @return
     */
    public static int getSubArrLengthFromGivingStart(int[] arr,int startIndex,Map<Integer,Integer> map){

        Integer value = map.get(startIndex);
        if (value != null){
            return value;
        }

        int maxLen = 1;

        if (startIndex < arr.length-1){
            for (int i = startIndex + 1; i < arr.length; i++) {
                if (arr[i] > arr[startIndex]){
                    int tmp = getSubArrLengthFromGivingStart(arr,i)+1;
                    maxLen = tmp>maxLen?tmp:maxLen;
                }
            }
        }
        //如果传入startIndex = arr.length-1,也即从最后一个元素开始找,显然是1
        //放入缓存中
        map.put(startIndex,maxLen);
        return maxLen;
    }

    /**
     * 改进为非递归 
     * 时间复杂度o(n^2),比一开始的指数级好太多了
     * @param arr
     * @return
     */
    public static int getSubArrLengthFromGivingStartAdvanced(int[] arr){

        Map<Integer,Integer> map = new HashMap<>();

        for (int i = arr.length-1; i >= 0; i--) {//每次循环计算从序号i开始的最长递增子序列的长度
            int maxLen = 1;
            //如果i是最后一个元素,则显然最长递增子序列的长度就是1。continue结束本次循环
            if (i == arr.length-1){
                map.put(i,maxLen);
                continue;
            }

            for (int j = i+1; j < arr.length; j++) {
                if (arr[i] < arr[j] ){
                    int tmp = map.get(j)+1;
                    maxLen = tmp > maxLen? tmp:maxLen;
                }
            }
            map.put(i,maxLen);
        }

        //上面算出了从每个index触发开头的最长递增子序列的长度,这里选其中最大的返回
        int max = 1;
        for (int i = 0; i < arr.length; i++) {
            Integer tmp = map.get(i);
            max = tmp>max?tmp:max;
        }
        return max;
    }

}

标签:tmp,map,arr,缓存,int,length,maxLen,startIndex,穷举
From: https://blog.csdn.net/m0_63246220/article/details/140584264

相关文章

  • Starmap 与 tqdm 结合?
    我正在做一些并行处理,如下所示:withmp.Pool(8)astmpPool:results=tmpPool.starmap(my_function,inputs)其中输入如下所示:[(1,0.2312),(5,0.52)...]即int和float的元组。代码运行良好,但我似乎无法将其包装在加载栏(tqdm)上,例如可以使用imap方......
  • 使用 FFpyplayer 帧和 QPixmap 以及 MPEG-TS 格式的 UDP 流时出现追赶延时缓冲和滞后
    我正在尝试根据此帖子中找到的代码来构建我的用例。但是,我在使用pythonFFpyPlayer时遇到了麻烦;对于传统的ffplay,我没有这些问题。运行我的应用程序时,我注意到一种追赶延时缓冲效果,视频播放速度显着加快,然后恢复到正常速度。在某些视频中,我发......
  • 使用 openstreetmap 数据创建行人图的左侧和右侧
    我正在尝试通过python使用openstreetmap数据创建行人图。该图是使用OSMnx库创建的。每条边代表每条路,但行人实际上可以走在道路的右侧或左侧。我需要有左侧和右侧来获取交叉节点并将它们相互连接。我尝试将左右两侧的边缘分开,但没有成功。你们中有人有任何经验或知道......
  • 同时使用线程本地变量以及对象缓存的问题
    同时使用线程本地变量以及对象缓存的问题如有转载请著名出处:https://www.cnblogs.com/funnyzpc/p/18313879前面  前些时间看别人写的一段关于锁的(对象缓存+线程本地变量)的一段代码,这段代码大致描述了这么一个功能:外部传入一个key,需要根据这个key去全局变量里面找是否存在,如......
  • 关于service层自动生成mapper接口时为静态方法的解决办法
    在Service层自动生成Mapper方法的时候出现带方法体的静态方法而不是抽象方法,例如mapper中生成这样的方法:staticIntegerordersStatistics(Mapmaps){  }原因可能有两种1、mapper层未加mapper注解2、Service层调用的是Mapper类而不是使用Mapper生成的mapper对象错......
  • 【Memcached核心功能篇】缓存生命周期
    目录缓存生命周期管理数据过期策略时间戳和生存时间(TTL)自动刷新和更新机制示例1:使用TTL设置数据过期时间示例2:实现缓存穿透的解决方案示例3:解决缓存击穿问题缓存生命周期管理   缓存生命周期管理是任何使用缓存技术的系统中至关重要的一个方面。涉及到数据的......
  • Java中的多级缓存设计与实现
    Java中的多级缓存设计与实现大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在现代应用程序中,多级缓存设计是一种常见的性能优化技术。多级缓存通过在不同层次上缓存数据来减少对底层存储系统的访问次数,提高系统的整体性能。本文将展示如何在Java中设计......
  • redis缓存雪崩,击穿,穿透,到底是什么?
    Redis缓存雪崩、击穿、穿透是缓存机制中常见的问题,这些问题都可能对系统的性能和稳定性产生严重影响。缓存雪崩是指当缓存层承载大量请求并有效保护存储层时,如果缓存层由于某些原因无法提供服务(如缓存数据大面积失效),导致所有请求都直接到达存储层,进而造成存储层请求量急剧增加......
  • Memcached集群管理:构建高可用性缓存系统
    Memcached集群管理:构建高可用性缓存系统目录引言Memcached简介高可用性缓存系统的需求Memcached集群架构单点故障与负载均衡数据分片构建Memcached集群环境准备配置和部署高可用性策略服务器故障处理数据一致性监控与维护性能监控日常维护总结1.引......
  • java基础学习:序列化之 - ObjectMapper
    文章目录一、介绍二、主要功能三、使用方法官网:一、介绍ObjectMapper是Jackson库中的一个核心类,用于在Java对象和JSON数据之间进行转换。Jackson是一个流行的Java库,用于处理JSON数据。它提供了灵活的方式来序列化和反序列化Java对象,即将Java对象转换......