zoukankan      html  css  js  c++  java
  • 最长上升子序列(LIS)的 普通解法 和 二分解法

    状态转移方程:

    dp [ i ]  = max { 1 , dp[ j ] + 1  }     ( j < i   && a[ j ] < a[ i ]   )

    先来介绍普通解法:复杂度O(n^2)

    题目: 输入n个数,求出其中的最长上升子序列。

    #include<iostream>
    using namespace std;
    
    int main()
    {
    	int a[100];//输入数字 
    	int dp[100];//用于储存以a[i]结尾的最长上升子序列的 长度 
    	int n,m,j,k,i,T;
    	cin>>n;
    	for (i=0;i<n;i++)
    	{
    		cin>>a[i];
    		dp[i] = 1;//一开始,所有的长度都为 1 
    	}
    	int ans = -1;//记录d[i]中最大的数,也就是答案 
    	for (i=0;i<n;i++)
    	{
    		for (j=0;j<i;j++)
    		{
    			if (a[i]>a[j] && dp[j]+1 > dp[i])//对每一个a[i]遍历它之前的,如果可以把 
    			{								//这个a[i]插在后面,还能让dp[i]增大,那么就加上去 
    				dp[i] = dp[j] + 1;
    			}
    		}
    		ans = max(ans,dp[i]);//记录最大的ans 
    	}
    	cout<<ans<<endl;
    	return 0;
    }

     再来介绍二分算法:复杂度O(n*logn)

    这里介绍下  STL 的 upper_bound( ) 函数的用法:

    upper_bound( a,a+n ,x) : 在数组 a 中 找到 第一个  大于 x 的 数字的 指针

    那么 upper_bound( a,a+n ,x) - a   就表示 第一个  大于 x 的 数字的   数组的下标

    注意: 数组 a 赋值时要从 下标 0 开始,才能使用这个函数。

    思路:

    用 lis 数组储存 最长上升子序列的 序列 的最优情况 。

    在大于lis [ len ]时 len++,在小于lis[ len ]时可以将arr[ i ]在 lis 中的数进行替换掉。所以此算法主要是在不停的找最合适的起点和最合适的终点。

    举例:

    输入数组:2 1 5 3 6 4 8 9 7  显而易见 答案为:5

    以下是 lis 数组的变化情况 :

    第一步:2                   替换

    第二步:1                   替换

    第三步:1 5                加入

    第四步:1 3                替换

    第五步:1 3 6             加入

    第六步:1 3 4             替换

    第七步:1 3 4 8           加入

    第八步:1 3 4 8 9        加入

     第九步:1 3 4 7 9       替换

    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    int main()
    {
    	int a[10000];
    	int lis[10000];
    	int n,m,j,k,i,T;
    	cin>>n;
    	
    	for (i=0;i<n;i++)
    	cin>>a[i];
    	
    	int len = 0;
    	lis[0] = a[0];
    	for (i=1;i<n;i++)
    	{
    		if (a[i] > lis[len])
    		lis[++len] = a[i];
    		else
    		{
    			int pos = upper_bound(lis,lis+len,a[i]) - lis;
    			lis[pos] = a[i];
    		}
    	}
    	cout<<len+1<<endl;.//最后答案 +1  
    	return 0;
    } 
     
     
     
     
  • 相关阅读:
    信号量Semaphore的使用
    Future和FutureTask
    阻塞队列和线程池
    Java多线程基础
    Java常用方法
    Scanner和BufferedReader的区别和用法
    QT学习笔记9:QTableWidget的用法总结
    WordPress 建站教程:新手搭建 WordPress个人博客图文教程(完全版)
    Let's do it
    jdk alternatives
  • 原文地址:https://www.cnblogs.com/Romantic-Chopin/p/12451160.html
Copyright © 2011-2022 走看看