数组中最长的升序子序列(动态规划问题)

The longest Increasing Subsequence (LIS) 
给定一个序列,找到这个序列的一个最长的子序列,使得子序列的所有元素是升序的,且元素之间的相对位置不变(元素可以在原数组中不相邻,但是相对位置不变) 
比如, LIS for { 10, 22, 9, 33, 21, 50, 41, 60, 80 } 是 6,LIS 是 {10, 22, 33, 50, 60, 80}.

分析 
arr[0…n-1]是输入,然后L(i)是到元素i为止 LIS 的长度,也就是arr[i]作为 LIS 的最后一个元素时 LIS 的长度,那么用递归形式 L(i) 可以写作:

for(j<i)
    if(arr[j]<arr[i]) L(i) = {1+Max( L(j) )}
if(j == 1) //递归的终止条件
    L(i) = 1

所以这个问题可以将其分解为 subproblems 用递归进行解决:

#include <iostream>
using namespace std;

int LIS(int *arr, int n, int *max_ref)
{
  if(n==1) return 1;
  int res, longest_here=1;

  for(int i = 1; i<n; ++i)
  {
    res = LIS(arr, i, max_ref);
    if(arr[i-1]<arr[n-1] && res+1>longest_here)
      longest_here = res+1;
  }

  if(*max_ref < longest_here)
    *max_ref = longest_here;

  return longest_here;
}

int main()
{
    int arr[] = { 10, 22, 9, 33, 21, 50, 41, 60 };
    int n = sizeof(arr)/sizeof(arr[0]);
    int max=1;
    LIS( arr, n, &max);
    cout<<max<<endl;
    return 0;
}

非递归方法,这个需要开辟额外的存储空间。

int LIS2(int *arr,int n)
{
  int *longest_here = new int[n]();
  longest_here[0] = 1;
  int max = 1;
  for(int i = 1; i<n; ++i)
  {
    for(int j = 0; j<i; ++j)
    {
      if(arr[j]<arr[i] && longest_here[j]+1>longest_here[i])
    longest_here[i] = longest_here[j]+1;

    }
    if(longest_here[i]>max)
      max = longest_here[i];
  }

  delete []longest_here;
  return max;

}

wiki上边有时间复杂度为O(nlog(n))的解法

时间: 2024-08-02 09:26:00

数组中最长的升序子序列(动态规划问题)的相关文章

求数组中最长递增子序列

编程之美有一道关于数组中最长递增子序列,题目如下: 写一个时间复杂度尽可能低的程序,求一个一维数组(N个元素)中最长递增子序列的长度. 例如在序列1,-1,2,-3,4,-5,6,-7中,其最长的递增子序列的长度为4(如1,2,4,6),从该书给的例子我们可以知道的是其最长的递增子序列可以不连续的. 作者利用动态规划方法给了三种解法. 解法一: 根据无后效性的定义,各阶段按照一定的次序排列好之后,对于某个给定阶段的状态来说,它以前各阶段的状态无法直接影响它未来的决策,而只能间接地通过当前状态来影

求数组中最长递增子序列的长度

个人信息:就读于燕大本科软件工程专业 目前大三; 本人博客:google搜索"cqs_2012"即可; 个人爱好:酷爱数据结构和算法,希望将来从事算法工作为人民作出自己的贡献; 编程语言:C++ ; 编程坏境:Windows 7 专业版 x64; 编程工具:vs2008; 制图工具:office 2010 powerpoint; 硬件信息:7G-3 笔记本; 真言 怒冲北京,为理想前行. 题目 解法 使用工具栈单枝遍历数组(思路源于工具栈可以双枝遍历二叉树的方法) 栈里存放的是数组的下

编程之美-数组中最长递增子序列(包括输出)

#include <iostream> #define N 8 using namespace std; int main(){ int a[N]={1,-1,2,-3,4,-5,6,-7}; int lis[N]; int result[N];//结果 for(int i=0;i<N;i++) result[i]=0; for(int i=0;i<N;i++) { lis[i]=1; for (int j=0;j<i; j++) { if( a[i]> a[j] &a

编程之美5:求数组中最长递增子序列

最近楼楼被男朋友带着玩dota,有点上瘾,终于在昨天晚上作出了一个重大的决定,shift+delete删掉warIII文件夹,从此退出dota的明争暗斗.不过最近看男票已经将战场从11转到了topcoder,嗯,这是个好现象,希望楼楼也能跟着玩儿起来. 理想是美好的,唉,可是楼主还在编程之美的初级阶段啊.话不多说了,希望自己加油加油再加油!!(^o^)/~ 今天要看的一道题目是求数组中最长递增子序列. 题目简介: 写一个时间复杂度尽可能低的程序,求一个一维数组(N)个元素中的最长递增子序列的长度

[算法]求数组中最长递增子序列长度

思路: 1.开辟数组L,L[i]记录的为a[0]~a[i]的最长递增子序列长度 2.开辟数组maxV,maxV[i]记录的为长度为i的各递增子序列的最后一个元素的最小值,譬如有子序列 1,2,4 1,2,5 则maxV[3] = 4 3.使用maxLen记录当前的最长递增子序列长度 4.转移方程: L[i+1] = max{1,L[j]+1] , a[i] > maxV[j] && j <= maxLen int LIS(int* a, int n){ int* maxV =

华为机试测试- 求有序数组中最长的等差序列

原题目是求一个无序数组中最长的等差数列. 求随机数构成的数组中找到长度大于=3 的最长的等差数列, 输出等差数列由小到大:如果没有符合条件的就输出格式:输入[1,3,0,5,-1,6]输出[-1,1,3,5] 思路: 1.排序 2.d的取值范围是[0,max-min],共有max-min+1种情况 3.对每一种情况进行查找 4.对于公差d,要求最长的等差序列,需要两个循环,一个外循环从头到尾遍历,内循环从外循环的起始遍历点开始利用公式 arr[i]=arr[start]+len*d,假如符合就长

编程之美---求数组中最长递增子序列

写一个时间复杂度尽可能低的程序,求一个一维数组(N个元素)中最长递增子序列的长度. 解法一:用动态规划,找出以当前元素结尾的最大递增子序列长度.dp[i+1] = max{1, dp[i]+1} ,array[i+1]>array[k] ,k<=i; 复杂度为o(n*n + n). 解法二:另外开一个数组保存长度为i的递增子序列的长度最大的最后一个元素最小的值,然后当处理数组中第i个元素时,从当前最大子序列的长度开始递减,依次寻找直到arrary[i]大于当前最大子序列长度的末尾元素值,然后更

【难】求数组中最长递增子序列,时间复杂度O(nlogn)

题目:<编程之美> P194 写一个时间复杂度尽可能低的程序,求一个数组(length个元素)中最长递增子序列的长度. 注意,本题认为最长递增子序列可以有相等的元素,如 (1,2,2,3,3,4,5,6). 时间复杂度为O(n^2)的程序思路很简单,参考书上的解法一.针对O(n^2)的解法进行改进,利用有序数组的二分查找,可以使得时间复杂度降低.本题的难点在于,建立一个长度为length+1的数组MinV,MinV[i]代表着长度为i的递增子序列最大元素的最小值.而且数组MinV是升序的,理解

2.16 求数组中最长递增子序列

题目: 求一个一维数组(N个元素)中最长递增子序列的长度 DP题 代码如下: #include <iostream> using namespace std; const int MAXN = 100000; const int INF = 10000000; int minV[MAXN], lis[MAXN], Array[MAXN]; int n; //lis[i]表示从第i个元素开始的最长序列的长度 //minV[i]表示所有长度为i的序列中,最大的元素的最小值 //Array这个数组代