Longest increasing subsequence(LIS)最长增序子序列二分查找

O(nlogn)解法来自纸牌游戏

创建一个堆数组
比较当前指向的元素和每个堆的第一个元素,计算出比当前元素小的堆数量
若当前元素比所有堆的第一个元素大,创建新的堆并加入到堆数组中,否则将当前元素加入到第“比当前元素小的堆数量”个堆
分类完后将每个堆反序然后对每个堆再做耐心排序
最后将每个堆串接并存储回原本的数组
耐心分类与称为弗洛伊德游戏的纸牌游戏密切相关。 这个游戏非常类似于之前描绘的游戏:
发出的第一张牌形成一张由单张牌组成的新牌。
每张后续卡片放置在一些现有的堆上,其顶部卡的值不大于新卡的值,或者放在所有现有桩的右侧,从而形成新的堆。
当没有剩余的牌可以交换时,游戏结束。
游戏的目标是尽可能少地完成游戏。 与耐心排序算法的不同之处在于,不需要在允许的最左边的堆上放置新卡。 耐心分类构成了玩这个游戏的贪婪策略。
Aldous和Diaconis建议将9个或更少的桩定义为n = 52的获胜结果,其发生概率约为5%。
用于找到最长增加子序列的算法
首先,执行如上所述的排序算法。 桩的数量是最长子序列的长度。 每当一张牌放在一堆纸上时,将一个后指针放在前一堆的顶牌上(假设它具有比新牌更低的价值)。 最后,按照最后一堆中顶部牌的反向指针来恢复最长长度的递减子序列; 它的反向是对增长最长的子序列算法的回答。

patience sort代码实现

#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;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值