我找到了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)中找到增长最长的子序列的算法。如果我尝试使用少量测试用例,它似乎工作。但我仍然无法弄清楚它的正确性逻辑。此外,它对我来说看起来并不那么直观。
任何人都可以帮助我深入了解为什么这个算法正常工作吗?
答案 0 :(得分:4)
声明:对于每个i,当前集合的长度等于最大增加子序列的长度。
证明:让我们使用归纳法:
基本情况:平凡无误。
归纳假设:假设我们已经处理了i-1个元素,并且集合的长度是LIS [i-1],即第一个i-1元素可能的LIS长度。 / p>
归纳步骤:在集合中插入元素数组[i]将导致两种情况。
A [i]&gt; = set.last():在这种情况下,A [i]将是集合中的最后一个元素,因此LIS [i] = LIS [i-1] +1
A [i]&lt; set.last():在这种情况下,我们将A [i]插入到set和knock off元素中,该元素在排序顺序中大于A [i]。 LIS [i] = LIS [i-1] + 1(加A [i])-1(去除一个elem> A [i])。这是真的。因此证明了。
解释大局。将A [i]插入到集合中将添加到LIS [i-1]或将创建自己的LIS,这将是从第0个位置到第i个元素位置的元素。
答案 1 :(得分:2)
How to determine the longest increasing subsequence using dynamic programming?
请先在那里阅读我的解释。如果仍不清楚,请阅读以下内容:
该算法保留每个长度的LIS
的最低可能结束数。通过保持最低数字,您可以以最大方式扩展LIS
。我知道这不是证明,但也许对你来说很直观。