画圆的沙滩

亦简亦美

最长递增子序列

编程之美2.16节。较容易想到的方法是O(n^2)的。这里有一个细节没有使用到,假设记录下所有长度的子序列结果,那么我们可以保证长度为n的子序列尾元素一定大于等于长度为n-1的子序列尾元素,否则的话,我们可以从长度为n的子序列中获取一个n-1的子序列,将之前的结果覆盖。利用这个性质,我们可以获得一个O(nlogn)的算法:

template<class It>
vector
<typename iterator_traits<It>::value_type>
lis(It first, It last) {
typedef iterator_traits
<It>::value_type value_type;
vector
<value_type> ends;
vector
< vector<value_type> > seqs;

for (It it = first; it != last; ++it) {
vector
<value_type>::iterator pit = lower_bound(ends.begin(), ends.end(), *it);
if (pit == ends.end()) {
ends.push_back(
*it);
seqs.push_back(seqs.size()
? seqs.back(): vector<value_type>());
seqs.back().push_back(
*it);
}
else {
*pit = *it;
size_t d
= distance(ends.begin(), pit);
seqs[d]
= d? seqs[d-1]: vector<value_type>();
seqs[d].push_back(
*it);
}
}

return seqs.back();
}

int main() {
int n;
while (cin>>n) {
if (!n) break;
vector
<int> in;
while (n--) *back_inserter(in) = *istream_iterator<int>(cin);
vector
<int> seq = lis(in.begin(), in.end());

for (size_t i = 0; i < seq.size(); ++i) {
if (i) cout<<' ';
cout
<<seq[i];
}
cout
<<'\n';
}
return 0;
}

posted on 2011-03-21 19:18  acmaru  阅读(201)  评论(0编辑  收藏  举报

导航