牛牛的数列

链接:https://ac.nowcoder.com/acm/problem/13134
来源:牛客网

题目

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

思路

题目的想法是改变数列中的一个数字后,可以使该数字的前面和后面严格递增序列合并成一个更大的数列。例如数组[7 2 3 1 5 6],该数组有三个严格递增数列分别是[7]、[2 3] 和[1 5 6],那么对于序列[7]和[2 3]来说,要合并他们的话,必须改变数字2且2前面数字要小于2后面的数字。同理看序列[2 3]和[1 5 6],要合并两个序列必须保证1的前面一个数字小于1后面那个数字,这样改变1后可以将俩个严格递增的序列合并成更大的序列。所以该题目解法的基本思路是查看数组中的每个严格递增序列是否能和后一个严格递增序列进行合并

为了较快找到一个严格递增的序列,设置两个数组left[]和right[]。left[]数组是记录以第i个数字为结尾的严格递增连续子序列的长度,right[]数组是记录以第i个数字为开头的严格递增连续子序列的长度。还是以数组a = [7 2 3 1 5 6]为例,left = [1 1 2 1 2 3],right = [1 2 1 3 2 1],那么我们可以在o(1)时间内确定两个递增序列合并后的长度:在数组a中,要合并序列[7]和[2 3],则判断a[1]=2的前一个数字a[0]和后一个数字a[2]是否满足a[0] < a[2],因为不满足所以无法通过修改a[1]的数字合并两个序列;再判断是否能够合并[2 3]和[1 5 6],因为a[2] < a[4],所以可以通过修改a[3]这个数字合并两个序列,合并后的长度为left[2] + right[4] + 1。

总结

要想通过改变一个数字后得到更大的严格上升子序列,那么必然是在改变一个数字后能将两个相邻的严格上升子序列进行合并得到一个更大的严格上升子序列,所以该题可以化简为判断相邻的两个严格上升子序列是否能合并,若能合并则记录合并后最大的长度。

java代码

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        long[] arr = new long[n];
        for(int i=0; i<n; i++) {
            arr[i] = in.nextInt();
        }
        long[] left = new long[n], right = new long[n];
        left[0] = 1;
        for (int i = 1; i < n; i++) {
            left[i] = arr[i] > arr[i - 1] ? left[i - 1] + 1 : 1;
        }
        right[n-1] = 1;
        for (int i = n - 2; i >= 0; i--) {
            right[i] = arr[i] < arr[i + 1] ? right[i + 1] + 1 : 1;
        }

        long max = 1;
        for (int i = 1; i < n - 1; i++) {
            if (arr[i - 1] < arr[i + 1]) {
                max = max < left[i - 1] + right[i + 1] + 1 ? left[i - 1] + right[i + 1] + 1 : max;
            }
        }
        System.out.println(max);
    }
}
原文地址:https://www.cnblogs.com/liuyongyu/p/13496437.html