雁过无痕

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::

《编程之美》读书笔记172.16 求数组中最长递增子序列

 

思路:每处理一个数,都可以将这个数插入到已经找到的某个递增子序列(假设包含无限个长度为0的空序列)后,使其长度增加1,处理完毕后,这些长度最大值即为所求。

 

具有相同长度i+1的递增子序列,若这些序列的最后一个数最小值为min_v[i],其所在的序列为A,则若某个数能插入到序列A后面,必然能插入到其它相同长度的递增子序列后面,而能否插入到序列A后面,仅由min_v[i]值决定,因而只要维护min_v[i]值就够了。

 

当前数必然可以插入到某个长度为j0<=j<=len len为已找到的最长递增子序列长度)的序列后,使得旧的min_v[j+1](假设该数组每个值初始化为无穷大)大等于该数,必须更新min_v[j+1]等于该数。如果序列是严格递增的,则只能找到一个这样的j值;如果序列是非严格递增的,可能找到不止一个j,取所有j值最大的即可,因为插入到其它的,min_v[j+1]值不会发生改变。

 

具体过程:

min_v[i]保存当前已找到的所有长度为i的递增子序列的最后一个数的最小值。

len保存当前已找到的最长递增子序列的长度。

对输入src[n], 显然 min_v[0]=src[0],这时len=1

从输入数组的第二个数开始,(假设要求所求子序列严格递增)

比较当前值value和长度为len的子序列最后一个值(min_v[len-1])

1value > min_v[len-1],则可以将value加在已找到的最长递增子序列后面,得到长度为len+1的更长的递增子序列,即有min_v[len]=value,且len值加1

2value <= min_v[len-1],则可以找到0<=j<=len-1满足: value <= min_v[j]

   如果j=0,则value可组成长度为1的子序列,

如果j>0,则可以将value加在由min_v[j-1]决定的长度为j的子序列后,得到新的长度为j+1的子序列。

均有min_v[j]=value

 

如果要输出一个最长递增子序列,可以用一个数组info[i]记录第i+1src[n]数能得到最长递增子序列的长度(info[i]等于前面要写入value的位置在min_v的下标加1)。再同时扫描一遍这两个数组,从后往前扫描,先找到第一个对应长度为len的数A,然后找到第一个对应长度为len-1且比A小的数,以此类推找出所有的数。

 



size_t lis(
const int src[], size_t sz)
{
  
if (src==NULL || sz<1return 0
  
//min_v[i]为当前已找到的长度为i+1的所有递增子序列的最后一个值的最小值。
  vector<int> min_v(sz);
  min_v[
0]=src[0];
  
//len为当前已找到的最长递增子序列的长度
  size_t i,len=1;
  
int value;
  
for (i=1; i<sz; ++i) {
    value
=src[i];
    
//假设递增子序列是严格递增    
    if (value>min_v[len-1]) min_v[len++]=value;
    
else *lower_bound(&min_v[0],&min_v[len], value)=value;
  }

  
return len;
}


posted on 2010-08-16 00:39 flyinghearts 阅读(1918) 评论(2)  编辑 收藏 引用 所属分类: 编程之美

评论

# re: 《编程之美》读书笔记17: 2.16 求数组中最长递增子序列 2011-07-03 00:30 burself
这个实现貌似跟书上的解法二是一样的。书上的解法三提到可以利用二分查找加速把时间降到O(n*lgn),不是很明白,并且觉得作者好像是把MaxVal数组和LIS数组弄混了,当i<j时,MaxVal[i]<MaxVal[j],但LIS[i]不一定小于LIS[j].  回复  更多评论
  

# re: 《编程之美》读书笔记17: 2.16 求数组中最长递增子序列 2011-07-07 22:39 flyinghearts

求数组中最长递增子序列,我知道有 两种O(n lg n) 算法,这是其中之一。
原理是: 当访问到第k个元素时,所有长度均为j (j < k)的最长递增子序列,只记录一个 排序后最小的。

可以证明,这样处理后,长度为1、2、3 ... k - 1 的最后一个元素是呈递增排列的, 当处理第k个元素时,只对某个长度的最长递增子序列有影响,可以通过二分查找找到该长度。

  回复  更多评论
  


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理