最长递减子序列--动态规划

本文介绍了一种基于动态规划思想求解最长递减子序列问题的方法,详细阐述了算法的实现过程,并提供了完整的C++代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

例如:有一个序列,例如 9 8 2 1 7 5 3 4 3 2 1.
     求出最长的递减子序列。如本例的结果就是:9 8 7 5 4 3 2 1。

分析:

        可采用动态规划的思想进行解答,时间复杂度为O(n^2).

       设原数组为a[1....n]。另设一数组d[1....n],其中d[i]表示从第i个元素开始(一定包含第i个元素),到整个数组末尾的子序列 a[i...n]中的最长递减子序列的长度。
       则本问题就是要在求出d[1]的同时,恢复出最优解。

   下面给出递推式:

d[i]的值分两种情况:
1、当i=n时,d[i]=1。即最后一个元素的序列的最大递减子序列中只有它自己。


2、当i<n时,d[i]=max{d[k]| i<k<=n 且a[i]>a[k]} +1。解释意思为,包含第i个元素的序列a[i...n]的最大子序列依赖于i后面所有的序列中比a[i]小(满足递减
特性),且最大的d[k](满足最 优特性)值再加1(加上a[i]元素)。在给d[i]赋值的时候只需记录p[i]=k,既可以作为parent属性恢复出解。

具体实现的话,开两个数组d[n],p[n],外层循环从后往前选取i,内层循环从i往后寻找最优的k,双循环遍历即可求出所有的d[i]。然后 再进行一次O(n)操作,找出最大的d[max]。恢复解的话,可以从p[max]开始,依次恢复出各个解。

复制代码
 1 #include <iostream.h> 
 3 void longest_decrease_sub(int *a, int size)
 4 {     
 6     int *d=new int[size]; //分配内存空间    
 7     int *p=new int[size];  //分配内存空间     
 9     d[size-1]=1;     
11     for(int i=size-1;i>=0;i--)
12     {         
14         int max=0;         
16         int index=0;         
18         for(int j=i;j<size;j++)
19         {             
21             if(a[i]>a[j] && max <d[j])
22             {                 
24                 max=d[j];                 
26                 index=j;                 
28             }             
30         }         
32         if(max==0)
33         {             
35             d[i]=1;             
37             p[i]=-1;             
39         }
40         else
41         {             
43             d[i]=max+1;             
45             p[i]=index;             
47         }         
49     }
50     
51     //寻找最大子序列的起始下标     
53     int max=0;     
55     int max_index=0;     
57     for( i=0;i<size;i++)
58     {        
60         if(d[i]>max)
61         {             
63             max=d[i];             
65             max_index=i;             
67         }         
69     }
70     
71     //从最大子序列的下标开始 输出子序列    
72     cout<<"\n最长递减子序列的长度为:"<<d[max_index]<<",最长子序列为:"<<ends;     
74     for( i=max_index;i!=-1;i=p[i])
75     {         
77         cout<<a[i]<<" "<<ends;         
79     }
80     
81     delete [] d;     
83     delete [] p;     
85 }
86 
87 void main()
88 {
89     int data[10]={1,2,5,4,3,2,7,8,9,0};
90     longest_decrease_sub(data,10);
91 }
### 动态规划解决最长递减子序列 (LDS) 动态规划是一种通过将复杂问题分解成更简单的子问题来解决问题的技术。对于最长递减子序列(Longest Decreasing Subsequence, LDS),可以利用动态规划的思想构建解决方案。 以下是基于 Python 的动态规划方法实现的代码示例: #### 实现代码 ```python def longest_decreasing_subsequence(sequence): n = len(sequence) if n == 0: return [] # 初始化 dp 数组,dp[i] 表示以 sequence[i] 结尾的最长递减子序列长度 dp = [1] * n # prev 数组用于记录路径以便于回溯得到具体子序列 prev = [-1] * n # 遍历数组填充 dp 和 prev for i in range(1, n): for j in range(i): if sequence[j] > sequence[i]: # 如果前面某个数大于当前数,则可能构成递减关系 if dp[j] + 1 > dp[i]: dp[i] = dp[j] + 1 prev[i] = j # 记录前驱索引 # 找到 dp 中的最大值及其索引 max_length = max(dp) index = dp.index(max_length) # 使用 prev 数组重建最长递减子序列 lds = [] while index != -1: lds.append(sequence[index]) index = prev[index] lds.reverse() # 反转列表获得正确的顺序 return lds # 测试用例 sequence = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] result = longest_decreasing_subsequence(sequence) print(f"输入序列: {sequence}") print(f"最长递减子序列: {result}") ``` 上述代码实现了动态规划的核心逻辑[^1]。`dp` 数组存储的是以每个位置结尾的最长递减子序列的长度,而 `prev` 数组则帮助我们追踪具体的子序列成员。 #### 复杂度分析 该算法的时间复杂度为 \(O(n^2)\),其中 \(n\) 是输入序列的长度。这是因为我们需要两层嵌套循环来更新 `dp` 数组中的每一个元素。空间复杂度为 \(O(n)\),因为需要额外的空间来保存 `dp` 和 `prev` 数组[^2]。 --- #### 解释与扩展说明 动态规划的关键在于状态转移方程的设计以及边界条件的处理。在这个例子中,状态转移方程定义如下: \[ \text{dp}[i] = \max(\text{dp}[j] + 1),\quad \forall j < i,\; \text{if}\;\text{sequence}[j] > \text{sequence}[i]. \] 这表示如果存在一个之前的位置 \(j\) 满足其对应的数值较大,则可以通过延长这个子序列的方式增加当前位置的最优解长度[^3]。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值