最长增加子序列[O(nlogn)]的算法如何工作?

时间:2013-12-14 20:41:20

标签: algorithm correctness lis proof-of-correctness

我找到了The Hitchhiker’s Guide to the Programming Contests中提到的算法(注意:此实现假设列表中没有重复项):

set<int> st;
set<int>::iterator it;
st.clear();

for(i=0; i<n; i++) {

  st.insert(array[i]); it=st.find(array[i]);

  it++; if(it!=st.end()) st.erase(it);
}

cout<<st.size()<<endl;

这是一种在O(NlogN)中找到增长最长的子序列的算法。如果我尝试使用少量测试用例,它似乎工作。但我仍然无法弄清楚它的正确性逻辑。此外,它对我来说看起来并不那么直观。

任何人都可以帮助我深入了解为什么这个算法正常工作吗?

2 个答案:

答案 0 :(得分:4)

声明:对于每个i,当前集合的长度等于最大增加子序列的长度。

证明:让我们使用归纳法:

基本情况:平凡无误。

归纳假设:假设我们已经处理了i-1个元素,并且集合的长度是LIS [i-1],即第一个i-1元素可能的LIS长度。 / p>

归纳步骤:在集合中插入元素数组[i]将导致两种情况。

  1. A [i]&gt; = set.last():在这种情况下,A [i]将是集合中的最后一个元素,因此LIS [i] = LIS [i-1] +1

  2. A [i]&lt; set.last():在这种情况下,我们将A [i]插入到set和knock off元素中,该元素在排序顺序中大于A [i]。 LIS [i] = LIS [i-1] + 1(加A [i])-1(去除一个elem> A [i])。这是真的。因此证明了。

  3. 解释大局。将A [i]插入到集合中将添加到LIS [i-1]或将创建自己的LIS,这将是从第0个位置到第i个元素位置的元素。

答案 1 :(得分:2)

How to determine the longest increasing subsequence using dynamic programming?

请先在那里阅读我的解释。如果仍不清楚,请阅读以下内容:

该算法保留每个长度的LIS的最低可能结束数。通过保持最低数字,您可以以最大方式扩展LIS。我知道这不是证明,但也许对你来说很直观。