📌  相关文章
📜  通过给定数组两端的元素最大化最长非递减数组的长度(1)

📅  最后修改于: 2023-12-03 15:42:03.435000             🧑  作者: Mango

最长非递减数组问题

问题描述

给定一个长度为n的数组arr,通过改变数组arr中两端的元素,使得该数组的最长非递减子序列长度最大化。

解法
方法一

动态规划

该问题可以转化为一个最长上升子序列问题,具体做法如下:

  1. 接受两个参数 数组 arr数组长度 n
  2. 构建一个数组 dp 用来记录到达 i 位置时的最长非递减子序列长度。
  3. 初始化 dp[i]=1(每个元素本身都是一个非递减子序列)。
  4. i=1n-1 依次遍历,对于每个 arr[i] ,从 j=0i-1 依次遍历,当 arr[j] <= arr[i] 时,更新 dp[i] = max(dp[i], dp[j] + 1)
  5. 返回数组 dp 中的最大值。

这个做法的时间复杂度为 $O(n^2)$,需要优化。可以通过使用二分查找进行优化。

方法二

二分查找+贪心

该方法利用了二分查找和贪心思想,具体做法如下:

  1. 接受两个参数 数组 arr数组长度 n
  2. 构建一个数组 dp 用来记录到达 i 位置时的最长递增子序列长度。
  3. 初始化 len=1,和数组 d 保存长度为 len 的最长递增子序列的末尾元素。
  4. 依次遍历数组 arr 的每个位置 i,在 d 数组中查找第一个大于等于 arr[i] 的位置 k,再将 arr[i] 赋值给 d[k],更新 dp[i]=k+1
  5. 如果 arr[i] > d[len],说明 arr[i] 可以接在最长递增子序列的后面,更新 len = len + 1,并将 arr[i] 放到 d 数组最后。
  6. 返回数组 dp 的最大值。

该方法的时间复杂度为 $O(n\log n)$。

代码实现
方法一
def max_increase_length(arr, n):
    dp = [1] * n
    for i in range(1, n):
        for j in range(i):
            if arr[j] <= arr[i]:
                dp[i] = max(dp[i], dp[j]+1)
    return max(dp)
方法二
import bisect

def max_increase_length(arr, n):
    d = [arr[0]]
    dp = [1] * n
    for i in range(1, n):
        if arr[i] > d[-1]:
            d.append(arr[i])
            dp[i] = len(d)
        else:
            k = bisect.bisect_left(d, arr[i])
            d[k] = arr[i]
            dp[i] = k + 1
    return max(dp)
总结

本文介绍了两种求解最长非递减子序列的算法,并给出了相应的代码实现。其中,方法二基于二分查找和贪心思想,时间复杂度较小,建议在实际开发中使用。