求數組中最長遞增子序列(編程之美2.16)

#ifndef _LGONGEST_INCREMENTAL_SEQUENCE_H_ 
#define _LGONGEST_INCREMENTAL_SEQUENCE_H_

#include <vector>
#include <algorithm>
using namespace std;

//編程之美2.16
//最長遞增子序列,使用動態規劃的時間複雜度爲O(n^2).
//但是通過剪枝可以大大減少比較的次數。

//主要思想是:
//1.可以使用一個結構來記錄一個長度串中的末位信息,而不是一個元素對應一個長度信息。
//	這樣,長度串跟元素是一對多的關係。
//	如果LIS[i]有多個序列,比如如果LIS[2]的序列可能是-1,2和1,10
//	那麼對於序列中的下一個值3,4,5,6,12來說,它們都能使用-1,2來構成更長的串,
//	所以LIS[i]應該是長度爲i的串中末尾數字的最小值
//2.應該看到,如果i<j,那麼LIS[i]<LIS[j],爲什麼這麼說呢?因爲如果LIS[i] >= LIS[j]
//	的話,我們就可以把LIS[j]放入到LIS[i]的末尾,從而LIS[j] == LIS[i]矛盾了。

template<typename T>
struct longest_incremental_sequence_comparator
{
	const bool operator()(const T& t1, const T& t2) const
	{
		return t1 < t2;
	}
};

template<typename T>
size_t longest_incremental_sequence(const vector<T>& array)
{	
	vector<T> LIS;
	LIS.reserve(array.size());
	longest_incremental_sequence_comparator<T> c;
	for (size_t i = 0; i != array.size(); i++)
	{//
		const T& t = array[i];

		//由於是有序的,所以使用upper_bound找到第一個比它小的
		vector<T>::iterator itr = upper_bound(LIS.begin(), LIS.end(), t, c);

		if (itr == LIS.end())
		{//最長子序列增加了
			LIS.push_back(t);
		}
		else
		{//更新它的下一個
			if (*itr > t)
			{//
				*itr = t;
			}
		}
	}

	return LIS.size();
}

void test_longest_incremental_sequence()
{
	int arr[] = {1,-1,2,-3,4,-5,6,7};
	vector<int> a(arr, arr+sizeof(arr)/sizeof(arr[0]));
	size_t max_length = longest_incremental_sequence(a);
	cout << max_length << endl;
}

#endif




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章