O(nlogn)解法来自纸牌游戏
创建一个堆数组
比较当前指向的元素和每个堆的第一个元素,计算出比当前元素小的堆数量
若当前元素比所有堆的第一个元素大,创建新的堆并加入到堆数组中,否则将当前元素加入到第“比当前元素小的堆数量”个堆
分类完后将每个堆反序然后对每个堆再做耐心排序
最后将每个堆串接并存储回原本的数组
耐心分类与称为弗洛伊德游戏的纸牌游戏密切相关。 这个游戏非常类似于之前描绘的游戏:
发出的第一张牌形成一张由单张牌组成的新牌。
每张后续卡片放置在一些现有的堆上,其顶部卡的值不大于新卡的值,或者放在所有现有桩的右侧,从而形成新的堆。
当没有剩余的牌可以交换时,游戏结束。
游戏的目标是尽可能少地完成游戏。 与耐心排序算法的不同之处在于,不需要在允许的最左边的堆上放置新卡。 耐心分类构成了玩这个游戏的贪婪策略。
Aldous和Diaconis建议将9个或更少的桩定义为n = 52的获胜结果,其发生概率约为5%。
用于找到最长增加子序列的算法
首先,执行如上所述的排序算法。 桩的数量是最长子序列的长度。 每当一张牌放在一堆纸上时,将一个后指针放在前一堆的顶牌上(假设它具有比新牌更低的价值)。 最后,按照最后一堆中顶部牌的反向指针来恢复最长长度的递减子序列; 它的反向是对增长最长的子序列算法的回答。
#include <iostream>
#include <vector>
#include <stack>
#include <iterator>
#include <algorithm>
#include <cassert>
template <class E>
struct pile_less {
bool operator()(const std::stack<E> &pile1, const std::stack<E> &pile2) const {
return pile1.top() < pile2.top();
}
};
template <class E>
struct pile_greater {
bool operator()(const std::stack<E> &pile1, const std::stack<E> &pile2) const {
return pile1.top() > pile2.top();
}
};
template <class Iterator>
void patience_sort(Iterator first, Iterator last) {
typedef typename std::iterator_traits<Iterator>::value_type E;
typedef std::stack<E> Pile;
std::vector<Pile> piles;
// sort into piles
for (Iterator it = first; it != last; it++) {
E& x = *it;
Pile newPile;
newPile.push(x);
typename std::vector<Pile>::iterator i =
std::lower_bound(piles.begin(), piles.end(), newPile, pile_less<E>());
if (i != piles.end())
i->push(x);
else
piles.push_back(newPile);
}
// priority queue allows us to merge piles efficiently
// we use greater-than comparator for min-heap
std::make_heap(piles.begin(), piles.end(), pile_greater<E>());
for (Iterator it = first; it != last; it++) {
std::pop_heap(piles.begin(), piles.end(), pile_greater<E>());
Pile &smallPile = piles.back();
*it = smallPile.top();
smallPile.pop();
if (smallPile.empty())
piles.pop_back();
else
std::push_heap(piles.begin(), piles.end(), pile_greater<E>());
}
assert(piles.empty());
}
int main() {
int a[] = {4, 65, 2, -31, 0, 99, 83, 782, 1};
patience_sort(a, a+sizeof(a)/sizeof(*a));
std::copy(a, a+sizeof(a)/sizeof(*a), std::ostream_iterator<int>(std::cout, ", "));
std::cout << std::endl;
return 0;
}
————————————————
leetcode官方题解 二分查找
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int len = 1, n = (int)nums.size();
if (n == 0) {
return 0;
}
vector<int> d(n + 1, 0);
d[len] = nums[0];
for (int i = 1; i < n; ++i) {
if (nums[i] > d[len]) {
d[++len] = nums[i];
} else {
int l = 1, r = len, pos = 0; // 如果找不到说明所有的数都比 nums[i] 大,此时要更新 d[1],所以这里将 pos 设为 0
while (l <= r) {
int mid = (l + r) >> 1;
if (d[mid] < nums[i]) {
pos = mid;
l = mid + 1;
} else {
r = mid - 1;
}
}
d[pos + 1] = nums[i];
}
}
return len;
}
};