链接:https://ac.nowcoder.com/acm/problem/13142
来源:牛客网
题目描述
牛牛现在有一个n个数组成的数列,牛牛现在想取一个连续的子序列,并且这个子序列还必须得满足:最多只改变一个数,就可以使得这个连续的子序列是一个严格上升的子序列,牛牛想知道这个连续子序列最长的长度是多少。
输入描述:输入包括两行,第一行包括一个整数n(1 ≤ n ≤ 10^5),即数列的长度; 第二行n个整数a_i, 表示数列中的每个数(1 ≤ a_i ≤ 10^9),以空格分割。输出描述:
输出一个整数,表示最长的长度。示例1
6 7 2 3 1 5 6输出
5
去百度查了下什么叫做“严格上升的子序列”
https://baike.baidu.com/item/%E4%B8%A5%E6%A0%BC%E9%80%92%E5%A2%9E/5318845
递增(increasing)函数是指当函数的任何自变量增加的时候,函数值不减少。严格递增(strongly increasing)是指当函数任何自变量增加的时候函数值也增加。类似地,递减函数(decreasing)是指当函数的任何自变量增加的时候函数值不增加,严格递减(strongly decreasing)是指当函数任何自变量增加的时候函数值却减少。
解题思路:
- 本题需要考虑间断路径和不间断路径两种场景。所以定义Dep[n]和DepBreak[n]分别表示不间断路径和间断路径。
- 考虑到执行效率问题,需要从右到左完成动态规划,利用上一次的结果计算本次结果。(亲身尝试,暴力破解会超时)
解题步骤:
- 对于不间断的情况:在循环遍历第i个数字时,如果第i个数字不大于第i+1个数组(iNums[i]<=iNums[i+1]),则Dep[i]=Dep[i+1]+1,当然,因为这个是不间断的情况,所以DepBreak也要做同样的操作DepBreak[i]=DepBreak[i+1]+1。
- 对于间断的情况:在循环遍历第i个数字时,如果跨越1个数字后满足要求间断要求,则允许间断计数,即iNums[i]<=iNums[i+2],跨间断计数。
间断计数原则:基于无间断的结果Dep[i+2]直接加上2个。
此时要比较【Dep[i+2]+2】和【按照不间断的方法得到的DepBreak[i]】,大着才是间断情况的最大值。- 需要注意:暴力破解会超时、输入个数小于等于2时需要特殊处理。
import java.util.Arrays;
import java.util.Collections;
import java.util.Scanner;
/**
* @return maxLenth
*/
public class Main20201121_2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()){
// 输入
Integer n = sc.nextInt();
Integer[] iNums = new Integer[n];
Integer[] iDep = new Integer[n];
Integer[] iDepBreak = new Integer[n];
for (int i=0; i<n; i++){
iNums[i] = sc.nextInt();
iDep[i] = 1;
iDepBreak[i] = 1;
}
// 计算步长
if (n>2){
for (int i=n-2; i>=0; i--){
// 不间断情况
if (iNums[i] <= iNums[i+1]){
iDep[i] = iDep[i+1] + 1;
iDepBreak[i] = iDepBreak[i+1] + 1;
}
if (i == n-2 && iNums[i] > iNums[i+1]){
iDepBreak[i]++;
}
// 间断的情况
if (i<n-2){
if (iNums[i] <= iNums[i+2]){
iDepBreak[i] = Math.max(iDep[i+2]+2, iDepBreak[i]);
}
}
}
// 打印结果
System.out.println(Collections.max(Arrays.asList(iDepBreak)));
}
else // n<=2的情况做特殊处理
// 打印结果
System.out.println(String.valueOf(n));
}
}
}



京公网安备 11010502036488号