最长递增子串

https://www.nowcoder.com/practice/6d9d69e3898f45169a441632b325c7b4?tpId=37&tqId=21247&tPage=2&rp=&ru=/ta/huawei&qru=/ta/huawei/question-ranking

https://blog.csdn.net/u013309870/article/details/62037674

描述

给定一个整型数组,取出最小数量的数字,使得剩下的数组,呈现递增的趋势,求最长的子串长度

输入

5 6 7 1 2 8

输出

4(即 5 6 7 8)

思路

动态规划

  1. 先求出原数组各个值对应的递增次序
    • 5 6 7 1 2 8 原数组
    • 1 2 3 1 2 4 递增次序
    • 递增次序什么意思呢?
      1. 就比如上面的5 6 7 是一个递增子串,那么对应的次序就是1 2
      2. 后面的1 2又是一个递增子串,次序又变成了1 2 3
      3. 最后一个8 既可以是5 6 7 的子串,又可以是 1 2的子串,这里就需要比较7对应的次序和2对应的次序哪个大,显然7对应的次序是3要大一些,所以8的次序就是4
      4. 递增次序也可理解为当前数的最长递增子串长度
    • 如何求各个数的递增序列?
      1. 声明一个int[] dp,原数组为int[] nums,保存原数组中各个数对应的最长递增子串长度(也就是上面的递增次序),全都赋值1(所有的次序都是从1开始累加)
      2. 遍历原数组nums[i],找到dp[0]到dp[i-1]之间的最大值dp[j],并且要满足nums[j]<nums[i],于是dp[i] = dp[j]+1

代码

public static int[] findUpSubstr(int[] nums){
        int[] dp = new int[nums.length];
        dp[0] = 1;
        for(int i=1;i<dp.length;i++){
            dp[i] = 1;
            for(int j=0;j<i;j++){
                if(nums[j]<nums[i]){
                    //必须要和当前的值比较,如果直接赋值dp[j]+1会导致后面满足nums[j]<nums[i]的数覆盖
                    //这一步变相的保存了dp[0]到dp[i-1]之间的最大值dp[j]
                    dp[i] = Math.max(dp[i],dp[j]+1);
                    //dp[i] = dp[j]+1;
                }
            }
        }
        return dp;
    }

这是上面两个连接的结合,加上了输出最后的递增序列

import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext()){
            int num = sc.nextInt();
            int[] nums = new int[num];
            for(int i=0;i<num;i++){
                nums[i] = sc.nextInt();
            }
            int[] upDp = findUpSubstr(nums);
            //输出最后的递增序列
            //getUpAry(nums,upDp);
            int[] lowDp = findLowSubstr(nums);
            int length=0;
            for(int i=0;i<nums.length;i++){
                length = Math.max(length,upDp[i]+lowDp[i]);
            }
            System.out.println(nums.length-length+1);
        }
    }
    
    public static int[] findUpSubstr(int[] nums){
        int[] dp = new int[nums.length];
        dp[0] = 1;
        for(int i=1;i<dp.length;i++){
            dp[i] = 1;
            for(int j=0;j<i;j++){
                if(nums[j]<nums[i]){
                    //必须要和当前的值比较,如果直接赋值dp[j]+1会导致后面满足nums[j]<nums[i]的数覆盖
                    dp[i] = Math.max(dp[i],dp[j]+1);
                    //dp[i] = dp[j]+1;
                }
            }
        }
        return dp;
    }
    
    public static int[] findLowSubstr(int[] nums){
        int[] dp = new int[nums.length];
        dp[dp.length-1] = 1;
        for(int i=dp.length-2;i>=0;i--){
            dp[i] = 1;
            for(int j=dp.length-1;j>i;j--){
                if(nums[j]<nums[i]){
                    //必须要和当前的值比较,如果直接赋值dp[j]+1会导致后面满足nums[j]<nums[i]的数覆盖
                    dp[i] = Math.max(dp[i],dp[j]+1);
                    //dp[i] = dp[j]+1;
                }
            }
        }
        return dp;
    }
    
    public static void getUpAry(int[] nums,int[] dp){
        int index=0,len=0;
        //找到递增序列中的最后一个数的索引 index
        for(int i=0;i<nums.length;i++){
            if(len<dp[i]){
                len = dp[i];
                index = i;
            } 
        }
        //存放递增队列
        int[] ary = new int[len];
        //ary的索引
        int k = 0;
        ary[k++] = nums[index];
        //倒序查找 保证dp[i+1] = dp[i]+1并且nums[i+1]>nums[i]
        //index表示上一个满足条件的索引
        for(int i=index-1;i>0;i--){
            if(dp[index] == dp[i]+1 && nums[index]>nums[i]){
                ary[k++] = nums[i];
                index = i;
            }
        }
        for(int i=ary.length-1;i>=0;i--){
            System.out.print(ary[i]+" ");
        }
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值