【算法】算法测试题5:牛牛的数列:最长连续子序列

题目描述

链接:https://www.nowcoder.com/ques...
来源:牛客网

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

输入描述

输入包括两行,第一行包括一个整数n(1 ≤ n ≤ 10^5),即数列的长度;
第二行n个整数a_i, 表示数列中的每个数(1 ≤ a_i ≤ 10^9),以空格分割。

输出描述

输出一个整数,表示最长的长度。

示例1

输入
6 
7 2 3 1 5 6
输出
5

解题思路

分析:这道题目看上去没法下手,就当学习一个思路吧,首先根据当前数组顺着求一遍以每个位置作为结尾的连续最长递增子序列的长度值,再逆着求解以每个元素作为开头的连续最长递增子序列的长度值,然后根据这两组值来找连接点。具体就拿体重的例子来说,此时数组arr为
7 2 3 1 5 6,我们定义两个数组left
和right,left数组表示正着求以每个元素作为结尾的最长递增子序列的长度,而right数组表示逆着以每个元素作为开头的连续最长递增子序列的长度值,所以可以知道left[0]=1,表示以7结尾的目前最长的连续递增子序列的长度值就是1,依次left[1]=1,left[2]=2,left[3]=1,left[4]=2,left[5]=3;
而right[5]=1,right[4]=2,right[3]=3,right[2]=1,right[1]=2,right[0]=1;好了,到此为止两个辅助的数组已经求出,接下来就要找连接点了,是这样的,根据题目意思,我们要找一个子序列,而且之多改变一个数就可以形成严格的连续递增子序列,所以我们先盯住数组中2这个数,我们发现以7结尾的最长的连续递增子序列的长度为left[0],而以3开头的连续递增子序列长度为right[2],这样,我们其实不用管7和3之间的数到底是多少,是2也好,不是2也好,只要2前面的数7能够严格小于2后面的数3,说明通过改变7和3之间这个数至合适的数值则,这两部分就可以连成一个连续的严格递增子序列,所有,我们遍历所有这样的点,记录满足条件的最大的长度再加1即可。
https://blog.csdn.net/wwe4023...

JavaScript代码

JavaScript代码1(雏形)

let n = parseInt(readline());
let t1 = readline();
let t2 = new String(t1);
let line = t2.split(" ");
let arr =  new Array();
for(let i = 0; i < line.length; i++){
    arr[i] = parseInt(line[i]);
}
let left = new Array(n);
let right = new Array(n);
let ans = 0;
for(let i = 0; i < arr.length; i++){
    left[i] = computeLeft(i, arr);
}
for(let i = arr.length - 1; i >= 0; i--){
    right[i] = computeRight(i, arr);
}
for(let i = 1 ; i < arr.length-1; i++){
    if(arr[i-1] <  arr[i+1]){
        let sum = left[i-1] + right[i+1];
        if(sum > ans){
            ans = sum;
        }
    }
}

print(ans+1);

function computeLeft(pos, arr){
    let count = 1;
    for(let i = pos; i > 0; i--){
        if(arr[i] > arr[i-1]){
            count++;
        }else{
            return count;
        }
    }
    return count;
}

function computeRight(pos, arr){
    let count = 1;
    for(let i = pos; i < arr.length-1; i++){
        if(arr[i] < arr[i+1]){
            count++;
        }else{
            return count;
        }
    }
    return count;

}

JavaScript代码2(优化)

let n = parseInt(readline());
let t1 = readline();
let t2 = new String(t1);
let line = t2.split(" ");
let arr =  new Array();
for(let i = 0; i < line.length; i++){
    arr[i] = parseInt(line[i]);
}
let left = new Array(n);//以arr[i]结尾的连续序列长度
let right = new Array(n);//以arr[i]开头的连续序列长度
let ans = 0;
left[0] = 1;
right[0] = 1;
for(let i = 1; i < arr.length; i++){
    if(arr[i] > arr[i-1]){
        left[i] = left[i-1] + 1;
    }else{
        left[i] = 1;
    }
    //left[i] = computeLeft(i, arr);
}
for(let i = arr.length - 1; i >= 0; i--){
    if(arr[i] < arr[i+1]){
        right[i] = right[i+1]+1;
    }else{
        right[i] = 1;
    }
    //right[i] = computeRight(i, arr);
}
for(let i = 1 ; i < arr.length-1; i++){
    if(arr[i-1] <  arr[i+1]){
        let sum = left[i-1] + right[i+1];
        if(sum > ans){
            ans = sum;
        }
    }
}

print(ans+1);
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值