方法一(递归)

1.解题思路

  • 递归终止条件:向左寻找时,寻找到索引0终止;向右寻找时,到索引nums.length-1终止。
  • 递归如何推进:向左寻找时,如果大于左边元素,直接由左边索引子序列加一,否则重置为1;向右寻找时,如果小于右边元素,直接由右边索引子序列加一,否则重置为1。
  • 每一层递归返回什么:当前层的最长子序列长度。

2.代码实现

import java.util.*;

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int一维数组 
     * @return int
     */
    public int maxSubArrayLength (int[] nums) {
        int n=nums.length;
        if(n==1||n==2) return n;
        //记录满足条件的连续子序列长度
        int leftMax=nums[n-2]<100000?findLeft(nums,n-2)+1:findLeft(nums,n-2);
        int rightMax=nums[1]>1?findRight(nums,1)+1:findRight(nums,1);
        int res=Math.max(leftMax,rightMax);
        //如果左边的最大值小于右边的最小值,那连起来就是递增的
        for(int i=1;i<nums.length-1;i++){
            if(nums[i-1]+1<nums[i+1]){
                res=Math.max(res,findLeft(nums,i-1)+findRight(nums,i+1)+1);
            }
            else{
                res=Math.max(res,Math.max(findLeft(nums,i-1)+1,findRight(nums,i+1)+1));
            }
        }
        return res;
    }
    
    //从i索引开始寻找左边的最长连续上升子序列(包括i)
    private int findLeft(int[] nums,int i){
        if(i==0) return 1;
        //如果大于左边元素,直接由左边索引子序列加一
        if(nums[i]>nums[i-1]){
            return findLeft(nums,i-1)+1;
        }
        return 1;
    }
    
    //从i索引开始寻找右边的最长连续上升子序列(包括i)
    private int findRight(int[] nums,int i){
        if(i==nums.length-1) return 1;
        //如果小于右边元素,直接由右边索引子序列加一
        if(nums[i]<nums[i+1]){
            return findRight(nums,i+1)+1;
        }
        return 1;
    }
}

3.复杂度分析

  • 时间复杂度:在主循环体中,向左时,每次最多寻找i次,向右时,每次最多寻找(n-1-(i+1)+1)=n-i-1次,于是每次最多寻找(i+(n-i-1))=n-1次,总共有(n-2)*(n-1)次,所以时间复杂度是O(n2)。
  • 空间复杂度:需要额外深度为n的递归栈,所以空间复杂度为O(n)。

方法二(动态规划)

1.解题思路

  • 状态定义:left[i]表示索引i左边的最长子序列,right[i]表示索引i右边的最长子序列。
  • 初始化:索引i在0处时,只有一个元素,left[0]为1,索引i在num.length-1处时,只有一个元素,right[num.length-1]为1。
  • 状态转移:找左边的连续递增子序列时,如果大于左边的,在原来的基础上加一,否则重置为1;找右边的连续递增子序列时,如果小于右边的,在原来的基础上加一,否则重置为1。

动图展示: 图片说明

2.代码实现

import java.util.*;

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int一维数组 
     * @return int
     */
    public int maxSubArrayLength (int[] nums) {
        // 初始化dp数组
        int n=nums.length;
        if(n==1||n==2) return n;
        int[] left=new int[n];
        int[] right=new int[n];

        //找左边的连续递增子序列
        left[0]=1;
        for(int i=1;i<n;i++){
            //如果大于左边的,在原来的基础上加一
            if(nums[i]>nums[i-1]){
                left[i]=left[i-1]+1;
            }
            //重置为1
            else{
                left[i]=1;
            }
        }

        //找右边的连续递增子序列
        right[n-1]=1;
        for(int i=n-2;i>=0;i--){
            //如果小于右边的,在原来的基础上加一
            if(nums[i]<nums[i+1]){
                right[i]=right[i+1]+1;
            }
            //重置为1
            else{
                right[i]=1;
            }
        }


        int leftMax=nums[n-2]<100000?left[n-2]+1:left[n-2];
        int rightMax=nums[1]>1?right[1]+1:right[1];
        int res=Math.max(leftMax,rightMax);
        //如果左边的最大值加1小于右边的最小值,那连起来就是递增的
        for(int i=1;i<n-1;i++){
            if(nums[i-1]+1<nums[i+1]){
                res=Math.max(res,left[i-1]+right[i+1]+1);
            }
            else{
                res=Math.max(res,Math.max(left[i-1]+1,right[i+1]+1));
            }

        }
        return res;
    }
}

3.复杂度分析

  • 时间复杂度:三次遍历都是线性的,所以时间复杂度是O(n)。
  • 空间复杂度:需要额外大小为n的left数组和right数组,所以空间复杂度为O(n)。