Dynamic Programming | Set 1 (Overlapping Subproblems Property)Dynamic Programming | Set 2 (Optimal Substructure Property) 中我们已经讨论了重叠子问题和最优子结构性质,现在我们来看一个可以使用动态规划来解决的问题:最长上升子序列(Longest Increasing Subsequence(LIS))。

最长上升子序列问题,致力于在一个给定的序列中找到一个最长的子序列,该子序列中的元素按升序排列。例如,序列{10, 22, 9, 33, 21, 50, 41, 60, 80}的最长上升子序列的长度为6,最长上升子序列为{10, 22, 33, 50, 60, 80}。

Optimal Substructure:

假设arr[0..n-1]为输入数组,L(i)是以下标i结束的数组的最长上升子序列的长度,满足arr[i]是LIS的一部分,即arr[i]是该LIS中的最后一个元素,那么L(i)可以递归的表示为:

L(i) = { 1 + Max ( L(j) ) } where j < i and arr[j] < arr[i] and if there is no such j then L(i) = 1

要获得一个给定数组LIS的长度,我们需要返回 max(L(i)) where 0 < i < n

因此,LIS问题具有最优子结构性质,因此该问题可以使用子问题的方法来求解。

Overlapping Subproblems:

以下是LIS问题的一个简单递归版本程序。

  1. /* A Naive recursive implementation of LIS problem */
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4.  
  5. /* To make use of recursive calls, this function must return two things:
  6. 1) Length of LIS ending with element arr[n-1]. We use max_ending_here
  7. for this purpose
  8. 2) Overall maximum as the LIS may end with an element before arr[n-1]
  9. max_ref is used this purpose.
  10. The value of LIS of full array of size n is stored in *max_ref which is our final result
  11. */
  12. int _lis( int arr[], int n, int *max_ref)
  13. {
  14. /* Base case */
  15. if(n == 1)
  16. return 1;
  17.  
  18. int res, max_ending_here = 1; // length of LIS ending with arr[n-1]
  19.  
  20. /* Recursively get all LIS ending with arr[0], arr[1] ... ar[n-2]. If
  21. arr[i-1] is smaller than arr[n-1], and max ending with arr[n-1] needs
  22. to be updated, then update it */
  23. for(int i = 1; i < n; i++)
  24. {
  25. res = _lis(arr, i, max_ref);
  26. if (arr[i-1] < arr[n-1] && res + 1 > max_ending_here)
  27. max_ending_here = res + 1;
  28. }
  29.  
  30. // Compare max_ending_here with the overall max. And update the
  31. // overall max if needed
  32. if (*max_ref < max_ending_here)
  33. *max_ref = max_ending_here;
  34.  
  35. // Return length of LIS ending with arr[n-1]
  36. return max_ending_here;
  37. }
  38.  
  39. // The wrapper function for _lis()
  40. int lis(int arr[], int n)
  41. {
  42. // The max variable holds the result
  43. int max = 1;
  44.  
  45. // The function _lis() stores its result in max
  46. _lis( arr, n, &max );
  47.  
  48. // returns max
  49. return max;
  50. }
  51.  
  52. /* Driver program to test above function */
  53. int main()
  54. {
  55. int arr[] = { 10, 22, 9, 33, 21, 50, 41, 60 };
  56. int n = sizeof(arr)/sizeof(arr[0]);
  57. printf("Length of LIS is %d\n", lis( arr, n ));
  58. getchar();
  59. return 0;
  60. }

考虑以上实现,如下是当数组大小为4时的递归树,lis(n)为以n为最后一个元素时,数组的LIS的长度。

不难发现,其中有子问题被重复计算。因此,该问题具有重叠子结构性质,通过Memoization或者Tabulation,可以防止子问题的重复计算。如下,是LIS问题的tabluated实现。

  1. /* Dynamic Programming implementation of LIS problem */
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4.  
  5. /* lis() returns the length of the longest increasing subsequence in
  6. arr[] of size n */
  7. int lis( int arr[], int n )
  8. {
  9. int *lis, i, j, max = 0;
  10. lis = (int*) malloc ( sizeof( int ) * n );
  11.  
  12. /* Initialize LIS values for all indexes */
  13. for ( i = 0; i < n; i++ )
  14. lis[i] = 1;
  15.  
  16. /* Compute optimized LIS values in bottom up manner */
  17. for ( i = 1; i < n; i++ )
  18. for ( j = 0; j < i; j++ )
  19. if ( arr[i] > arr[j] && lis[i] < lis[j] + 1)
  20. lis[i] = lis[j] + 1;
  21.  
  22. /* Pick maximum of all LIS values */
  23. for ( i = 0; i < n; i++ )
  24. if ( max < lis[i] )
  25. max = lis[i];
  26.  
  27. /* Free memory to avoid memory leak */
  28. free( lis );
  29.  
  30. return max;
  31. }
  32.  
  33. /* Driver program to test above function */
  34. int main()
  35. {
  36. int arr[] = { 10, 22, 9, 33, 21, 50, 41, 60 };
  37. int n = sizeof(arr)/sizeof(arr[0]);
  38. printf("Length of LIS is %d\n", lis( arr, n ) );
  39.  
  40. getchar();
  41. return 0;
  42. }

注意,以上的动态规划解法需要的时间复杂度为O(n^2),实际上LIS问题有O(nLogn)的解法(see this)。在这边,我们并没有讨论O(nLogn)的解法,此处,只是用这篇文章来作为动态规划的一个简单例子。

补充一个最笨的方法:将所有的子序列使用dfs枚举出来,看其最大长度是多少,代码如下:

  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4.  
  5. void dfs(const vector<int> &input, vector<vector<int> > &ret, vector<int> &path, int pos) {
  6. if (pos == input.size()) {
  7. ret.push_back(path);
  8. return;
  9. }
  10.  
  11. for (int i = 0; i != 2; i++) {
  12. if (i == 0) {
  13. path.push_back(input[pos]);
  14. dfs(input, ret, path, pos + 1);
  15. path.pop_back();
  16. } else {
  17. dfs(input, ret, path, pos + 1);
  18. }
  19. }
  20. }
  21.  
  22. int main()
  23. {
  24. vector<int> input = {1,2,3};
  25. cout << "input.size() = " << input.size() << endl;
  26. vector<vector<int>> ret;
  27. vector<int> path;
  28.  
  29. dfs(input, ret, path, 0);
  30.  
  31. for (vector<vector<int> >::const_iterator itr = ret.begin(); itr != ret.end(); itr++) {
  32. cout << "--" << " ";
  33. for (vector<int>::const_iterator it = itr->begin(); it != itr->end(); it++) {
  34. cout << *it << " ";
  35. }
  36. cout << endl;
  37. }
  38. }
  39.  
  40. /*
  41. Output:
  42. -- 1 2 3
  43. -- 1 2
  44. -- 1 3
  45. -- 1
  46. -- 2 3
  47. -- 2
  48. -- 3
  49. --
  50. */

Dynamic Programming | Set 3 (Longest Increasing Subsequence)的更多相关文章

  1. Dynamic Programming | Set 4 (Longest Common Subsequence)

    首先来看什么是最长公共子序列:给定两个序列,找到两个序列中均存在的最长公共子序列的长度.子序列需要以相关的顺序呈现,但不必连续.例如,"abc", "abg", ...

  2. [Algorithms] Using Dynamic Programming to Solve longest common subsequence problem

    Let's say we have two strings: str1 = 'ACDEB' str2 = 'AEBC' We need to find the longest common subse ...

  3. [LeetCode] Longest Increasing Subsequence 最长递增子序列

    Given an unsorted array of integers, find the length of longest increasing subsequence. For example, ...

  4. [Leetcode] Binary search, DP--300. Longest Increasing Subsequence

    Given an unsorted array of integers, find the length of longest increasing subsequence. For example, ...

  5. [LeetCode] Number of Longest Increasing Subsequence 最长递增序列的个数

    Given an unsorted array of integers, find the number of longest increasing subsequence. Example 1: I ...

  6. [Algorithms] Longest Increasing Subsequence

    The Longest Increasing Subsequence (LIS) problem requires us to find a subsequence t of a given sequ ...

  7. LeetCode 300. Longest Increasing Subsequence最长上升子序列 (C++/Java)

    题目: Given an unsorted array of integers, find the length of longest increasing subsequence. Example: ...

  8. [LeetCode] 300. Longest Increasing Subsequence 最长递增子序列

    Given an unsorted array of integers, find the length of longest increasing subsequence. Example: Inp ...

  9. [LeetCode] 673. Number of Longest Increasing Subsequence 最长递增序列的个数

    Given an unsorted array of integers, find the number of longest increasing subsequence. Example 1: I ...

随机推荐

  1. sql server driver ODBC驱动超时

  2. halcon批量读取图片

    以前这个代码都是自己写,不仅繁琐,而且容易忘记.其实Halcon中提供了相关的方法.记录一下吧,其实很简单. 读取一个文件夹下的所有图片[助手]>[打开新的image acquisition ] ...

  3. spring学习1

    1.<context:property-placeholder/> :用于从外部属性文件中获取Bean的配置 <context:property-placeholder locati ...

  4. c#读取文本并生成txt

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  5. oracle数据链接

    using System; using System.Collections.Generic; using System.Data; using System.Data.OracleClient; u ...

  6. Win10系统进行远程桌面连接出现身份验证错误怎么办

    在win10系统中,自带有远程桌面连接功能,但是有时候会遇到一些问题,比如有不少用户反映说在进行远程桌面连接的时候,出现身份验证错误的情况,导致远程连接失败,接下来给大家分享一下Win10系统进行远程 ...

  7. SqlServer中的UNION操作符在合并数据时去重的原理以及UNION运算符查询结果默认排序的问题

    本文出处:http://www.cnblogs.com/wy123/p/7884986.html 周围又有人在讨论UNION和UNION ALL,对于UNION和UNION ALL,网上说的最多的就是 ...

  8. (转)VS2010反编译dll之后存在的resource修改为resx

    https://www.cnblogs.com/tangbaono1/p/6897183.html 1.找到安装VS的时候,存在的ResGen.exe,我的电脑是win7的,路径是在C:\Progra ...

  9. python中发送post请求时,报错“Unrecognized token 'xxxx': was expecting ('true', 'false' or 'null')”

    解决办法: 如请求参数为 data={“user”=“aaa”,“pwd”=“123456”,sign=“00000000000000”} 需要将参数data先做处理,调用函数datas=datajs ...

  10. 数据库启动windows

    1.上 MongoDB官网下载数据库,下载之后选择自己想放的文件夹要记住文件夹位置,比如我下载之后就放在D盘,改文件夹为 mongodb 2.启动之前要给mongodb指定一个文件夹,这里取名为&qu ...