最长连续递增序列的变种:最多允许删除k个元素的最长连续递增子序列
字数 858 2025-12-01 18:31:18

最长连续递增序列的变种:最多允许删除k个元素的最长连续递增子序列

题目描述
给定一个整数数组nums和一个整数k,找出最长连续递增子序列的长度,但允许最多删除k个元素。也就是说,我们可以删除最多k个元素来获得一个连续递增的子序列。

例如:
nums = [1, 3, 2, 4, 5, 2, 1], k = 1
输出:4
解释:删除元素2后得到[1, 3, 4, 5, 2, 1],其中[1, 3, 4, 5]是连续递增的,长度为4。

解题过程

步骤1:理解问题本质
我们需要找到一个最长的连续递增子序列,但允许最多跳过(删除)k个元素。这可以理解为在数组中找到一个窗口,窗口内最多有k个"破坏递增顺序"的元素。

步骤2:定义状态
我们使用滑动窗口+动态规划的思想:

  • 定义dp[i]表示以第i个元素结尾的最长连续递增子序列长度
  • 但这里我们更需要维护一个滑动窗口,使用双指针技巧

步骤3:滑动窗口解法

  1. 初始化left = 0, max_len = 1
  2. 对于每个right从1到n-1:
    • 如果nums[right] > nums[right-1],继续扩展窗口
    • 如果nums[right] <= nums[right-1],检查是否还能删除元素:
      • 如果已删除元素数 < k,可以继续
      • 否则需要移动左指针

步骤4:详细算法实现

def findLength(nums, k):
    n = len(nums)
    left = 0
    max_len = 1
    # 记录需要删除的元素数量
    delete_count = 0
    
    for right in range(1, n):
        # 如果当前元素大于前一个元素,直接扩展窗口
        if nums[right] > nums[right-1]:
            max_len = max(max_len, right - left + 1)
            continue
        
        # 当前元素破坏递增性,需要处理
        if delete_count < k:
            # 还可以删除元素
            delete_count += 1
            max_len = max(max_len, right - left + 1)
        else:
            # 无法再删除,移动左指针
            # 找到第一个破坏递增性的位置
            while left < right and delete_count >= k:
                # 如果左指针移动时跳过一个破坏点,减少delete_count
                if left < n-1 and nums[left] >= nums[left+1]:
                    delete_count = max(0, delete_count - 1)
                left += 1
            # 处理当前元素
            if nums[right] <= nums[right-1]:
                delete_count += 1
            max_len = max(max_len, right - left + 1)
    
    return max_len

步骤5:优化解法
上面的解法可能不够完善,我们使用更清晰的动态规划思路:

定义dp[i][j]:以i结尾,使用了j次删除操作的最长序列长度
状态转移:

  1. 不删除当前元素:
    if nums[i] > nums[i-1]:
    dp[i][j] = dp[i-1][j] + 1
    else:

    需要删除nums[i-1]或者跳过

    if j > 0:
    dp[i][j] = dp[i-1][j-1] + 1

步骤6:最终优化解法

def findLength(nums, k):
    n = len(nums)
    if n == 0:
        return 0
    
    # dp[i][j]: 以i结尾,使用了j次删除的最长长度
    dp = [[1] * (k+1) for _ in range(n)]
    max_len = 1
    
    for i in range(1, n):
        for j in range(k+1):
            # 情况1:nums[i]直接接在nums[i-1]后面
            if nums[i] > nums[i-1]:
                dp[i][j] = dp[i-1][j] + 1
            # 情况2:使用一次删除机会跳过破坏递增的元素
            elif j > 0:
                dp[i][j] = dp[i-1][j-1] + 1
            
            # 情况3:尝试连接更早的元素
            for p in range(i-2, max(-1, i-j-2), -1):
                if p >= 0 and nums[i] > nums[p] and j - (i-p-1) >= 0:
                    remaining_deletes = j - (i-p-1)
                    dp[i][j] = max(dp[i][j], dp[p][remaining_deletes] + 1)
            
            max_len = max(max_len, dp[i][j])
    
    return max_len

步骤7:最优解法(滑动窗口)

def findLength(nums, k):
    n = len(nums)
    left = 0
    max_len = 1
    # 记录窗口中破坏递增性的位置
    violations = []
    
    for right in range(1, n):
        if nums[right] <= nums[right-1]:
            violations.append(right)
        
        # 如果破坏点太多,移动左指针
        while len(violations) > k:
            # 移动左指针到第一个破坏点之后
            left = violations.pop(0) + 1
            # 重新计算破坏点
            temp = []
            for i in range(left, right):
                if nums[i] <= nums[i-1]:
                    temp.append(i)
            violations = temp
        
        max_len = max(max_len, right - left + 1)
    
    return max_len

这个解法的时间复杂度是O(n),空间复杂度是O(k),是最优的解决方案。

最长连续递增序列的变种:最多允许删除k个元素的最长连续递增子序列 题目描述 给定一个整数数组nums和一个整数k,找出最长连续递增子序列的长度,但允许最多删除k个元素。也就是说,我们可以删除最多k个元素来获得一个连续递增的子序列。 例如: nums = [ 1, 3, 2, 4, 5, 2, 1 ], k = 1 输出:4 解释:删除元素2后得到[ 1, 3, 4, 5, 2, 1],其中[ 1, 3, 4, 5 ]是连续递增的,长度为4。 解题过程 步骤1:理解问题本质 我们需要找到一个最长的连续递增子序列,但允许最多跳过(删除)k个元素。这可以理解为在数组中找到一个窗口,窗口内最多有k个"破坏递增顺序"的元素。 步骤2:定义状态 我们使用滑动窗口+动态规划的思想: 定义dp[ i ]表示以第i个元素结尾的最长连续递增子序列长度 但这里我们更需要维护一个滑动窗口,使用双指针技巧 步骤3:滑动窗口解法 初始化left = 0, max_ len = 1 对于每个right从1到n-1: 如果nums[ right] > nums[ right-1 ],继续扩展窗口 如果nums[ right] <= nums[ right-1 ],检查是否还能删除元素: 如果已删除元素数 < k,可以继续 否则需要移动左指针 步骤4:详细算法实现 步骤5:优化解法 上面的解法可能不够完善,我们使用更清晰的动态规划思路: 定义dp[ i][ j ]:以i结尾,使用了j次删除操作的最长序列长度 状态转移: 不删除当前元素: if nums[ i] > nums[ i-1 ]: dp[ i][ j] = dp[ i-1][ j ] + 1 else: 需要删除nums[ i-1 ]或者跳过 if j > 0: dp[ i][ j] = dp[ i-1][ j-1 ] + 1 步骤6:最终优化解法 步骤7:最优解法(滑动窗口) 这个解法的时间复杂度是O(n),空间复杂度是O(k),是最优的解决方案。