1. 程式人生 > 其它 >利用lower_bound()和upper_bound()解決最長嚴格(非)上升/下降子序列長度問題

利用lower_bound()和upper_bound()解決最長嚴格(非)上升/下降子序列長度問題

一、lower_bound()upper_bound()基操

lower_bound()STL,返回某一給定容器區間內第一個大於等於某給定數字x的數字的指標。

upper_bound()STL,返回某一給定容器區間內第一個大於某給定數字x的數字的指標。

以下均以lower_bound()為例

  1. 基本操作

    int a[11] = {0,1,2,3,4,5,6,7,8,9,10};
    int x = 5;
    int* p = lower_bound( x+1, x+10+1 , x );   //對於區間 [ a[1], a[10] ], 同 sort
    cout << p << endl;
    cout << *p << endl;
    cout << a[a-p] << endl;
    
  2. 更改比較方式

    void cmp( int a, int b )
    {
        return a > b;
    }
    
    int* p = lower_bound( x+1, x+10+1, x, cmp );  //由大於等於改為小於等於
    

    int* p = lower_bound( x+1, x+10+1, x, greater<int>() );  //由大於等於改為小於等於
    

二、基本思想與證明

以下以最長上升子序列為例

我們以dp[len]表示陣列a[len]中長度為len的上升子序列結尾的最小合法值。

a[i]大於b[len]:將a[i]直接續在b[]陣列之後。

a[i]

小於等於b[len]:在b[]中找到第一個大於等於a[i]的數,用a[i]替換它。

證明:

顯然(證畢)。

a[i]大於b[len],顯然將a[i]直接續在b[]陣列之後是合法的。

a[i]小於等於b[len],則b[]中第一個大於等於a[i]的數一定不可能比a[i]優。(上升序列x越小x越能接)。

(證畢)

三、實操

#include <bits/stdc++.h>

using namespace std;

int a[1000], dp[1000],n ,len;

int main()
{
	cin >> n; 
	for( int i = 1; i <= n; ++i )
		cin >> a[i];
		
//------------------------------------------------
		
	//最長上升子序列 	
	dp[1] = a[1]; len = 1;
	for( int i = 2; i <= n; ++i )
	{
	
		if( a[i] > dp[len] )
			dp[++len] = a[i];
			
		else
			*lower_bound( dp+1, dp+len+1, a[i] ) = a[i];
	}
	cout << len << endl;
	
//------------------------------------------------
	
	//最長下降子序列 
	dp[1] = a[1]; len = 1;
	for( int i = 2; i <= n; ++i )
	{ 
		if( a[i] < dp[len] )
			dp[++len] = a[i];
			
		else
			*lower_bound( dp+1, dp+len+1, a[i], greater<int>() ) = a[i];		 
	}
	cout << len << endl;
	
//------------------------------------------------

	//最長不降子序列 	
	dp[1] = a[1]; len = 1;
	for( int i = 2; i <= n; ++i )
	{
	
		if( a[i] >= dp[len] )
			dp[++len] = a[i];
			
		else
			*upper_bound( dp+1, dp+len+1, a[i] ) = a[i];
	}
	cout << len << endl;	
	
//------------------------------------------------
	
	//最長不升子序列 	
	dp[1] = a[1]; len = 1;
	for( int i = 2; i <= n; ++i )
	{
	
		if( a[i] <= dp[len] )
			dp[++len] = a[i];
			
		else
			*upper_bound( dp+1, dp+len+1, a[i], greater<int>() ) = a[i];
	}
	cout << len << endl;	
	
//------------------------------------------------

	return 0;
}