• 【动态规划】输出所有的最长递增子序列和字典序最小的


    leetcode 300

    根据
    leetcode的第300题:输出最长递增子序列的长度
    在这里插入图片描述

    f[i]表示以i结尾的最长递增子序列的长度

    //时间复杂度O(N*N)解法
    public int lengthOfLIS(int[] nums) {  
        if(nums==null||nums.length==0)  
            return 0;  
        int n=nums.length;  
        int[] f=new int[n];  
        int res=0;  
        for(int i=0;i<n;i++){  
            //最长子序列就只有它一个  
            f[i]=1;  
            for(int j=0;j<i;j++){  
                if(nums[j]<nums[i]&&f[j]+1>f[i])  
                    f[i]=f[j]+1;  
            }  
            res=Math.max(res,f[i]);  
        }  
        return res;  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    下面有两个变形题:
    输出所有的最长递增子序列
    输出字典序最小的最长递增子序列

    这两个题也可以使用动态规划来解,只不过状态数组改为记录以i为结尾的最长子序列

    输出所有的最长递增子序列

    使用HashMap>> record来记录状态
    key是坐标i,value是以i坐标为结尾的最长子序列,因为这个最长子序列可能会有多个,所以采用二维数组的方式

    //打印长度最长的所有子序列  
    public int allLIS(int[] nums) {  
        if (nums == null || nums.length == 0)  
            return 0;  
        int n = nums.length;  
        //record保存 以下标i为结尾的数字的最长递增子序列的集合,因为可能有多个,所以是二维数组  
        //将原来的记录长度的dp数组,改为记录子序列的hashMap  
        HashMap<Integer, List<List<Integer>>> record = new HashMap<>();  
        //统计最长长度  
        int max = 0;  
        for (int i = 0; i < n; i++) {  
            //i下标对应的二维数组  
            List<List<Integer>> tmpLists = new ArrayList<>();  
            //初始化长度为1,即只有它自己  
            int longest = 1;  
            //之后枚举从0~i-1,找到还长的i  
            for (int j = 0; j < i; j++) {  
                //得到i对应的二维数组,并遍历它的所有一维数组  
                List<List<Integer>> getLists = record.get(j);  
                for (int k = 0; k < getLists.size(); k++) {  
                    List<Integer> getList = getLists.get(k);  
                    //如果尾数字比当前的nums[i]小  
                    if (getList.get(getList.size() - 1) < nums[i]) {  
                        //如果长度+1后小于当前长度,结束当前遍历  
                        if(getList.size()+1<longest)  
                            continue;  
                        //如果长度+1大于或等于当前长度,拷贝此序列,并将nums[i]加到最后  
                        List<Integer> tmpList = new ArrayList<>();  
                        for (Integer tmp:getList){  
                            tmpList.add(tmp);  
                        }  
                        tmpList.add(nums[i]);  
                        if (getList.size() + 1 > longest) {  
                            //需要注意的是:如果长度更长,之前的二维数组舍弃,创建一个新的二维数组  
                            tmpLists = new ArrayList<>();  
                            tmpLists.add(tmpList);  
                            longest = tmpList.size();  
                        } else if (getList.size() + 1 == longest) {  
                            tmpLists.add(tmpList);  
                        }  
                    }  
                }  
            }  
            //如果没有满足条件的j,那就只能i自己一个序列  
            if (tmpLists.size() == 0) {  
                List<Integer> tmpList = new ArrayList<>();  
                tmpList.add(nums[i]);  
                tmpLists.add(tmpList);  
            }  
            record.put(i, tmpLists);  
            if (longest > max)  
                max = longest;  
        }  
        for (Map.Entry<Integer, List<List<Integer>>> entry : record.entrySet()) {  
            List<List<Integer>> resLists = entry.getValue();  
            //打印长度为max的所有序列  
            if (resLists.get(0).size() == max){  
                for (List<Integer> tmp : resLists) {  
                    System.out.println(tmp);  
                }  
            }  
        }  
        return max;  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    测试数据:
    在这里插入图片描述

    输出字典序最小的最长递增子序列

    使用二维数组来记录以i结尾的字典序最小的最长递增子序列,因为只有唯一的一个最小字典序,所以我们使用二维数组来保存序列就可以

        public int DictionoryOfLIS(int[] nums){  
            if (nums == null || nums.length == 0)  
                return 0;  
            int n = nums.length;  
            int max=0;  
            //因为只记录以i结尾的字典序最小的递增子序列,所以我们只使用二维数组就可以记录序列的状态  
            List<List<Integer>> record=new ArrayList<>();  
            //先初始化,方便后面操作  
            for(int i=0;i<n;i++){  
                record.add(new ArrayList<>());  
            }  
            record.get(0).add(nums[0]);  
            for (int i = 1; i < n; i++) {  
                //先假设最长长度为1  
                int longest=1;  
                for (int j = 0; j < i; j++) {  
                    //得到以坐标j为结尾的数组  
                    List<Integer> getList=record.get(j);  
                    if(getList.get(getList.size()-1)<nums[i]){  
                        //如果长度比longest还小,直接返回  
                        if(getList.size()+1<longest)  
                            continue;  
                        //如果长度大于等于longest,就先构造出该子序列  
                        List<Integer> tmplist=new ArrayList<>();  
                        for(Integer tmp:getList)  
                            tmplist.add(tmp);  
                        tmplist.add(nums[i]);  
                        //如果大于longest,直接替换  
                        if(getList.size()+1>longest){  
    //                        record.add(tmplist);  
                            record.set(i,tmplist);  
                            longest=tmplist.size();  
                        //如果等于,比较字典序,字典序小的保留  
                        }else if(getList.size()+1==longest){  
                            if(!dictoionary(record.get(i),tmplist)){  
                                record.set(i,tmplist);  
                            }  
                        }  
                    }  
                }  
                //如果i前面没有符合条件的数,那么序列就是它自己  
                if(record.get(i).size()==0){  
                    List<Integer> tmplist=new ArrayList<>();  
                    tmplist.add(nums[i]);  
                    record.set(i,tmplist);  
                }  
                //记录最长的序列  
                if(record.get(i).size()>max)  
                    max=record.get(i).size();  
            }  
            //返回字典序最小且最长的递增子序列  
            List<Integer> res=new ArrayList<>();  
            for (List<Integer> tmp:record) {  
                if(res.size()<tmp.size()){  
                    res=tmp;  
                }else if(res.size()==tmp.size()){  
                    if(!dictoionary(res,tmp))  
                        res=tmp;  
                }  
            }  
            System.out.println(res);  
            return max;  
        }  
      
        private boolean dictoionary(List<Integer> list, List<Integer> getList) {  
            for (int i = 0; i < getList.size(); i++) {  
                //如果原来的字典序比较大,就返回false  
                if(list.get(i)>getList.get(i))  
                    return false;  
            }  
            //如果原来的字典序较小,返回true  
            return true;  
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    在这里插入图片描述

  • 相关阅读:
    Java注释:单行、多行和文档注释
    计算机组成原理-主存储器与CPU的连接
    学习笔记|矩阵按键控制原理|数值转化为键码|密码锁|STC32G单片机视频开发教程(冲哥)|第十四集:矩阵按键原理及实践
    Netty 线程工作机制—— NioEventLoop
    EraseNet:End-to-End Text Removal in the wild
    1818. 绝对差值和-快速排序加二分查找
    ESP8266-Arduino编程实例-PCF8591数据采集驱动
    ssm医院挂号系统的设计与实现毕业设计源码211633
    2023年电工杯B题半成品论文使用讲解
    98. 验证二叉搜索树
  • 原文地址:https://blog.csdn.net/weixin_51574797/article/details/127127982