首页 > 试题广场 >

最长严格上升子数组(一)

[编程题]最长严格上升子数组(一)
  • 热度指数:2473 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定一个长度为n的正整数数组nums,可以任意改变数组的其中一个元素,改变的元素范围也在[1,100000]之内,然后返回nums的最长"严格上升"子数组的长度。
1.子数组是连续的,比如[1,3,5,7,9]的子数组有[1,3],[3,5,7]等等,但是[1,3,7]不是子数组
2.严格上升指在数组上任意位置都满足 nums[i] < nums[i+1],比如[1,2,2,3],其中[1,2,2]不是严格上升的子数组,[1,2]是的
数据范围:
要求: 空间复杂度 ,时间复杂度
示例1

输入

[7,2,3,1,5,6]

输出

5

说明

将1改为4,最长严格上升子数组为[2,3,4,5,6]      
示例2

输入

[1,2,3,4]

输出

4

说明

最长严格上升子数组为[1,2,3,4]      
示例3

输入

[1,2,2,3]

输出

3

说明

改变一个元素之后,最长严格上升子数组为[1,2,3]或者[2,3,4],长度都为3      

算法流程

用经典的动态规划求解,需要用到预处理技巧,所以会有O(n)的空间复杂度消耗。
  1. 构建两个dp数组dpLeftdpRight,其中的元素表示分别以数组中某个数结尾和开头的最长递增子数组长度,可以直接用O(n)时间复杂度的动态规划把这两个数组求出来。
  2. 然后遍历数组,检查是否可以通过修改nums[i]将左右两边的最长递增子数组连起来。如果不能连起来,就看nums[i]是修改完成为左边递增子数组的结尾能使递增子数组更长,还是修改完成为右边递增子数组的开头能使递增子数组更长。
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型一维数组 
     * @return int整型
     */
    public int maxSubArrayLengthTwo (int[] nums) {
        // 预处理
        int n = nums.length;
        if(n == 1) return 1;
        int[] dpLeft = new int[n];     // dpLeft[i]表示以nums[i]结尾的最长递增子数组长度
        dpLeft[0] = 1;
        for(int i = 1; i < n; i++){
            dpLeft[i] = nums[i] > nums[i - 1]? dpLeft[i - 1] + 1: 1;
        }
        int[] dpRight = new int[n];     // dpRight[i]表示以nums[i]开头的最长递增子数组长度
        dpRight[n - 1] = 1;
        for(int i = n - 2; i >= 0; i--){
            dpRight[i] = nums[i] < nums[i + 1]? dpRight[i + 1] + 1: 1;
        }
        int maxLen = 1;
        for(int i = 0; i < n; i++){
            if(0 < i && i < n - 1 && nums[i + 1] - nums[i - 1] > 1){
                // 左右两边的递增子数组可以接起来
                maxLen = Math.max(maxLen, dpLeft[i - 1] + dpRight[i + 1] + 1);
            }else{
                // 两边接不起来就看nums[i]接前面更长还是接后面更长
                if(i > 0){
                    maxLen = Math.max(maxLen, dpLeft[i - 1] + 1);
                }
                if(i < n - 1 && nums[i + 1] > 1){
                    // 由于是正数数组,后一个数比1大才有可能接起来
                    maxLen = Math.max(maxLen, dpRight[i + 1] + 1);
                }
            }
        }
        return maxLen;
    }
}

 复杂度分析

总共遍历了3遍数组,时间复杂度为O(n),开辟了两个dp数组,额外空间复杂度O(n)。
发表于 2021-12-21 15:08:53 回复(3)
不知道
发表于 2021-10-26 07:30:01 回复(1)
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型vector 
     * @return int整型
     */
    int maxSubArrayLengthTwo(vector<int>& nums) {
        // write code here
        int maxLen = 0;
        int lastLen = 0;
        int start = 0;
        for (int i = 0; i < nums.size(); ++i) {
            
            int pre = 0;
            if (i > 0) pre = nums[i - 1];
            if (nums[i] > pre) {
                //len++
                maxLen = max(maxLen, i - start + 1 + lastLen);//包含第i位 start-i的长度 加上 前一段的长度
            } else {
                maxLen = max(maxLen, i - start + (lastLen == 0 ? 1 : lastLen));//处理结束的可能 如果lastlen=0 表示并没有用到修改 可以+1(第i位)
                if (i + 1 >= nums.size() || nums[i+1] - pre > 1 || (i - 2 >= 0 && nums[i] - nums[i-2] > 1)) {
                    //能通过修改一个值 num[i] 或者 num[i-1] 连起来
                    //前一段的长度 i - start
                    lastLen = i - start;
                } else {
                    //不能完整的连起来
                    //但是可以修改一个值
                    //前一段能修改的话 lastlen = 1
                    lastLen = 1;
                    if (nums[i] == 1) lastLen = 0;
                }
                start = i;
            }
        }
        return maxLen;
    }
};

发表于 2021-10-17 13:28:21 回复(0)
真是巨无语,1123这个数组不能变成0123,说好的任意改变呢!!!
发表于 2022-01-22 10:09:51 回复(1)