蓝桥杯最长不下降子序列
时间: 2025-03-24 09:07:13 浏览: 38
关于蓝桥杯竞赛中最长不下降子序列的解法
最长不下降子序列问题是经典的动态规划问题之一,在蓝桥杯竞赛中有较多涉及。以下是针对该问题的具体解题思路和实现方法。
1. 动态规划的核心思想
对于最长不下降子序列(Longest Non-decreasing Subsequence, LNDS),可以通过定义一个数组 dp[]
来记录以每个位置结尾的最长不下降子序列长度。设输入序列为 arr[n]
,则状态转移方程为:
[ dp[i] = \max(dp[j]) + 1 \quad (0 \leq j < i \text{ and } arr[j] \leq arr[i]) ]
其中 ( dp[i] ) 表示以第 (i) 个元素结尾的最长不下降子序列长度[^2]。
最终的结果即为整个数组中的最大值 ( \max(dp[]) )[^2]。
2. 时间复杂度分析
朴素的动态规划解决方案的时间复杂度为 (O(n^2)),因为需要两层嵌套循环来计算每一个 (dp[i]) 的值。然而,通过引入二分查找技术,可以将时间复杂度降低到 (O(n\log n))[^2]。
改进后的核心思想是维护一个单调递增的辅助数组 tail[]
,并利用二分查找更新这个数组的内容。具体过程如下:
- 初始化
tail[0] = arr[0]
; - 对于后续的每个元素 (arr[i]),如果它大于当前
tail
数组的最大值,则将其追加至tail
后面;否则,找到第一个比 (arr[i]) 大的位置,并替换掉那个位置上的值。
这种方法不仅能够高效解决最长不下降子序列问题,还适用于其他类似的变种问题。
3. 实现代码示例
下面是基于 C++ 和 Python 的两种实现方式:
C++ 实现
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int computeLNDS(vector<int> &arr){
vector<int> tail;
for(auto num : arr){
auto it = lower_bound(tail.begin(), tail.end(), num);
if(it == tail.end()) {
tail.push_back(num); // 如果找不到合适的插入点,则扩展尾部
}
else{
*it = num; // 替换已有的较大值
}
}
return tail.size(); // 返回结果为 tail 的大小
}
int main(){
int n;
cin >> n;
vector<int> arr(n);
for(int &num : arr) cin >> num;
cout << computeLNDS(arr) << endl;
}
Python 实现
from bisect import bisect_left
def compute_LNDS(arr):
tail = []
for num in arr:
idx = bisect_left(tail, num)
if idx == len(tail):
tail.append(num) # 扩展尾部
else:
tail[idx] = num # 替换已有较大的值
return len(tail)
if __name__ == "__main__":
n = int(input())
arr = list(map(int, input().split()))
print(compute_LNDS(arr))
以上代码均采用了 (O(n\log n)) 的优化策略。
4. 进一步思考与优化建议
尽管上述方法已经非常高效,但在某些特殊场景下仍需注意以下几点:
- 当数据规模特别大时,应考虑内存占用以及 I/O 效率的影响。
- 若题目要求输出具体的子序列而非仅限长度,则需要额外保存路径信息以便回溯重建结果。
相关推荐















