算法练习-1:在长度为n的数组中找到一个连续子序列,该连续子序列满足最多只改变一个数,就可以使其成为一个严格上升的连续子序列,返回该连续子序列的最长长度


题目:牛牛现在有一个n个数组成的数列,牛牛现在想取一个连续的子序列,并且这个子序列还必须得满足:最多只改变一个数,就可以使得这个连续的子序列是一个严格上升的子序列,牛牛想知道这个连续子序列最长的长度是多少。

简述:在长度为n的数组中找到一个连续子序列,该连续子序列满足最多只改变一个数,就可以使其成为一个严格上升的连续子序列,返回该连续子序列的最长长度

思路:可以分别计算数组中每个元素在该位置的正序和逆序的连续子序列长度,然后遍历数组,当前位置的 ans_1 = 正序子序列长度+逆序子序列长度-1(当前位置重复计算),为当前位置到断点的最大子序列长度,若当前位置的后一个元素与前一个元素的差值大于2,则当前位置有成为断点的“潜力”,则计算前一个元素的 ans_2 = 正序子序列长度+后一个元素的逆序子序列长度+1(当前位置加入计算)。最后,比较ans, ans_1和ans_2的大小,返回最终值。

import java.util.*;

public class Main{

    public static void main(String[] args){
        
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[] nums = new int[n+2]; // n+2设置数组两头的边界,idx=0为最小值,idx=n+1为最大值
        nums[0] = Integer.MIN_VALUE; // 设置左边界
        
        for(int i = 1; i <= n; i++){
            nums[i] = in.nextInt();
        }
        
        nums[n+1] = Integer.MAX_VALUE; //设置右边界
        
        int[][] dp = new int[n+2][2];
        
        int key = 1;
        while(key <= n){
            // 正序当前位置连续序列长度,遇到断点重置长度为1
            dp[key][0] = nums[key] > nums[key-1] ? 1+dp[key-1][0] : 1;
            // 逆序当前位置连续序列长度
            dp[n-key+1][1] = nums[n-key+1] < nums[n-key+2] ? 1+dp[n-key+2][1] : 1;
            key++;
        }
        
        int ans = -1;
        
        for(int i = 1; i <= n; i++){
            // 若当前位置不是断点,则有最大子序列长度,-1是由于当前位置重复计算
            ans = Math.max(ans, dp[i][0] + dp[i][1] - 1);
            if(nums[i+1] - nums[i-1] > 1){
                // 当前位置可以成为断点,计算最大子序列长度,+1是由于当前位置没被计算,只计算了当前位置的前后元素的子序列长度的总和,所以需要加上当前位置(断点)。
                ans = Math.max(ans, dp[i-1][0] + dp[i+1][1] + 1);
            }
        }
        System.out.println(ans);
    }
}

标签:动态规划

代码参考:运行ID:62159990

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值