Algorithm 最长递增子序列(O(nlogn))
有一件事我不明白:Algorithm 最长递增子序列(O(nlogn)),algorithm,lis,Algorithm,Lis,有一件事我不明白: 为什么X[M[i]]是一个非递减序列?算法背后的基本思想是保持给定长度的列表以尽可能小的元素结尾。构建这样的序列 在已知的最后一个元素序列中查找前一个元素(假设其长度为k) 尝试将当前元素附加到此序列,并为k+1长度构建新的更好的解决方案 因为在第一步中,您搜索较小的值,然后是X[i],所以新的解决方案(对于k+1)将使最后一个元素的顺序大于或短 我希望它能有所帮助。让我们先看看n^2算法: dp[0] = 1; for( int i = 1; i < len; i++
为什么X[M[i]]是一个非递减序列?算法背后的基本思想是保持给定长度的列表以尽可能小的元素结尾。构建这样的序列
k
)k+1
长度构建新的更好的解决方案k+1
)将使最后一个元素的顺序大于或短
我希望它能有所帮助。让我们先看看n^2算法:
dp[0] = 1;
for( int i = 1; i < len; i++ ) {
dp[i] = 1;
for( int j = 0; j < i; j++ ) {
if( array[i] > array[j] ) {
if( dp[i] < dp[j]+1 ) {
dp[i] = dp[j]+1;
}
}
}
}
dp[0]=1;
对于(int i=1;i数组[j]){
if(dp[i]
现在改进发生在第二个循环中,基本上,您可以通过使用二进制搜索来提高速度。除了数组dp[],我们还有另一个数组c[],c非常特殊,c[i]表示:长度为i的最长递增序列的最后一个元素的最小值
sz = 1;
c[1] = array[0]; /*at this point, the minimum value of the last element of the size 1 increasing sequence must be array[0]*/
dp[0] = 1;
for( int i = 1; i < len; i++ ) {
if( array[i] < c[1] ) {
c[1] = array[i]; /*you have to update the minimum value right now*/
dp[i] = 1;
}
else if( array[i] > c[sz] ) {
c[sz+1] = array[i];
dp[i] = sz+1;
sz++;
}
else {
int k = binary_search( c, sz, array[i] ); /*you want to find k so that c[k-1]<array[i]<c[k]*/
c[k] = array[i];
dp[i] = k;
}
}
sz=1;
c[1]=数组[0]/*此时,大小1递增序列的最后一个元素的最小值必须为数组[0]*/
dp[0]=1;
对于(int i=1;ic[sz]){
c[sz+1]=数组[i];
dp[i]=sz+1;
sz++;
}
否则{
int k=binary_search(c,sz,array[i]);/*您希望找到k,以便c[k-1]这是来自的O(n*lg(n))解决方案(注意:此实现假设列表中没有重复项):
set-st;
set::迭代器;
圣克利尔();
对于(i=0;i我们需要维护递增序列的列表
通常,我们有一组不同长度的活动列表。我们将向这些列表中添加一个元素A[i]。我们将按长度的降序扫描列表(针对结束元素)。我们将验证所有列表的结束元素,以查找结束元素小于[i](下限值)的列表
我们的战略由以下条件决定,
1.如果[i]在所有活动列表的最终候选中最小,我们将开始长度为1的新活动列表。
2.如果一个[i]在所有活动列表的最终候选中是最大的,我们将克隆最大的活动列表,并将其扩展一个[i]。
3.如果[i]介于两者之间,我们将找到一个具有比[i]小的最大结束元素的列表。克隆此列表并将其扩展[i]。我们将丢弃与此修改列表长度相同的所有其他列表。
请注意,在我们构建活动列表的过程中,始终保持以下条件
较小列表的结束元素小于较大列表的结束元素。
举个例子就很清楚了,让我们从维基上举个例子:
{0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15}
A[0]=0.情况1.没有活动列表,请创建一个。
0.
--------------------------------------------------------------
A[1]=8.案例2.克隆和扩展。
0.
0,8.
--------------------------------------------------------------
A[2]=4.案例3.克隆、扩展和放弃。
0.
0,4.
0、8.丢弃
--------------------------------------------------------------
A[3]=12.案例2.克隆和扩展。
0.
0,4.
0,4,12.
--------------------------------------------------------------
A[4]=2.案例3.克隆、扩展和放弃。
0.
0,2.
0、4.丢弃。
0,4,12.
--------------------------------------------------------------
A[5]=10.案例3.克隆、扩展和放弃。
0.
0,2.
0,2,10.
0、4、12.丢弃。
--------------------------------------------------------------
A[6]=6.案例3.克隆、扩展和放弃。
0.
0,2.
0,2,6.
0、2、10.丢弃。
--------------------------------------------------------------
A[7]=14.案例2.克隆和扩展。
0.
0,2.
0,2,6.
0,2,6,14.
--------------------------------------------------------------
A[8]=1.案例3.克隆、扩展和放弃。
0.
0,1.
0、2.丢弃。
0,2,6.
0,2,6,14.
--------------------------------------------------------------
A[9]=9.案例3.克隆、扩展和放弃。
0.
0,1.
0,2,6.
0,2,6,9.
0、2、6、14.丢弃。
--------------------------------------------------------------
A[10]=5.案例3.克隆、扩展和放弃。
0.
0,1.
0,1,5.
0、2、6.丢弃。
0,2,6,9.
--------------------------------------------------------------
A[11]=13.案例2.克隆和扩展。
0.
0,1.
0,1,5.
0,2,6,9.
0,2,6,9,13.
--------------------------------------------------------------
A[12]=3.案例3.克隆、扩展和放弃。
0.
0,1.
0,1,3.
0、1、5.丢弃。
0,2,6,9.
0,2,6,9,13.
--------------------------------------------------------------
A[13]=11.案例3.克隆、扩展和放弃。
0.
0,1.
0,1,3.
0,2,6,9.
0,2,6,9,11.
0、2、6、9、13.丢弃。
--------------------------------------------------------------------
set<int> my_set;
set<int>::iterator it;
vector <int> out;
out.clear();
my_set.clear();
for(int i = 1; i <= n; i++) {
my_set.insert(a[i]);
it = my_set.find(a[i]);
it++;
if(it != my_set.end())
st.erase(it);
else
out.push_back(*it);
}
cout<< out.size();
//! card piles contain pile of cards, nth pile contains n cards.
int top_card_list[n+1];
for(int i = 0; i <= n; i++) {
top_card_list[i] = -1;
}
3
* 7 2
-------------------------------------------------------------
Pile of cards above (top card is larger than lower cards)
(note that pile of card represents longest increasing subsequence too !)
for(int i = 1; i < n; i++) { // outer loop
for(int j = 0; j < i; j++) { // inner loop
if(arr[i] > arr[j]) {
if(memo_len[i] < (memo_len[j]+1)) {
// relaxation
memo_len[i] = memo_len[j]+1;
result = std::max(result,memo_len[i]);
pred[i] = j;
}
}
}
}
for(int i = 1; i < n; i++) {
pile_height[i] = 1;
const int j = pile_search(top_card_list, arr, pile_len, arr[i]);
if(arr[i] > arr[j]) {
if(pile_height[i] < (pile_height[j]+1)) {
// relaxation
pile_height[i] = pile_height[j]+1;
result = std::max(result,pile_height[i]);
pile_len = std::max(pile_len,pile_height[i]);
}
}
if(-1 == top_card_list[pile_height[i]] || arr[top_card_list[pile_height[i]]] > arr[i]) {
top_card_list[pile_height[i]] = i; // top card on the pile is now i
}
}
inline static int pile_search(const int*top_card_list, const vector<int>& arr, int pile_len, int strict_upper_limit) {
int start = 1,bound=pile_len;
while(start < bound) {
if(arr[top_card_list[bound]] < strict_upper_limit) {
return top_card_list[bound];
}
int mid = (start+bound)/2 + ((start+bound)&1);
if(arr[top_card_list[mid]] >= strict_upper_limit) {
// go lower
bound = mid-1;
} else {
start = mid;
}
}
return top_card_list[bound];
}
int n;
cin>>n;//LENGTH OF ARRAY
vector<int>v(n);
for(int i=0;i<n;i++){
cin>>v[i];
}
vector<int>d(n+1,INT_MAX);//AUXILLARY ARRAY
for(int i=0;i<=n;i++){
*lower_bound(d.begin(),d.end(),v[i])=v[i];
}
for(int i=0;i<n;i++){
if(d[i]==INT_MAX){
cout<<i;//LENGTH OF LIS
exit(0);
}
}