按照题意,我们这里运用单调栈思想,选择使用lower_bound()函数来编写实现求最长上升子序列的长度,代码如下: #include <bits/stdc++.h> using namespace std; const int MAXN = 10010; int n,num[MAXN]; vector<int> st; int main(){ cin >> n; for(int i=0;i<n;i++){ cin >> num[i]...
对于前一个举例的单调栈,如果新加入的元素大于栈顶元素,我们是从栈顶for到栈底,直到找到第一个小于它的元素,那么要增加一个元素时间复杂度最坏是O(n)。所以要用上upper_bound或lower_bound函数去查找第一个小于它的元素(用数组模拟栈),然后直接用要插入的元素替换即可,当然,不用弹出之前的栈顶元素,它们还有作用。
事实上这是一种贪心的策略,当我们处理的元素比栈顶大时,因为栈是递增的,所以自然地将这个元素添加到最末,序列长度+1。 当处理到比栈顶元素小的元素时,我们不是选择丢弃它,而是用它去替换单调栈中第一个大于它的元素,用题目的例子来说,当我们处理到元素9时,当前的单调栈为{-7, 10},我们将10替换为9,这样...
/* 最长上升子序列I问题求解思路: 1、错误思路(已验证):使用单调栈<-适用范围 返回某一个数左边、右边最近的大于/小于该数的数 2、正确思路: 状态表示:dp[j]表示以数字序列中第i个数字结尾的上升子序列 集合属性:集合上升子序列的最大长度 状态转移方程:dp[j] = max(dp[j],dp[i]+1),其中 a[i]<a...
//单调栈+二分计算最长上身子序列的值 vector<int> q(arrs.size() + 1,-2e9); int len = 0; for(int i = 0; i < arrs.size(); i ++) { int l = 0, r = len; while(l < r) { int mid = l + r + 1 >> 1; if(q[mid] < arrs[i]) l = mid; ...
}intdl[maxn][fbin],o[fbin];//单调栈加入i时,踢那个点voidgetdl() {for(intzt=0;zt=1;i--)if(zt&(1<>1]+(zt&1); } }intmi[maxn],f[tbin];//0不存在,1存在且在单调栈,2存在且已出单调栈voiddivi(intzt,int&xx,int&yy)//该三进制是由(这个数是否存在)(这个数是否在单调栈里...
观察算法整体过程,这里的dp数组其实模拟了一个栈,栈顶元素是当前最长上升子序列的最小末尾,属于网上说的单调栈优化。 在第二个算法中我们可以通过在二分查找中改变“上确界”和“下确界”,以及在第一个算法中通过改变符号(“<”和“<=”或“>”、“>=”等),求出最长不下降、不上升、严格下降子序列等问题。
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。 我理解成了最长上升连续子序列 这样的话答案应该是3而不是实例种的4 虽然写错了 但还是把我使用单调栈方式写的最长连续子序列的代码贴出来 classSolution{public:intlengthOfLIS(vector<int>&nums){intn=nums.size();stack<int>in;intans=0,Ans=...
回到题目,我们发现,他只要我们求长度,所以我们可以模拟一个单调栈(曾经很多参考书说这是一个栈。实际上不是严格的栈,而是一个后进入的加在末尾,然后每次可以替换掉其中元素的序列。这个序列是单调递增的,保证结果就是所求的LIS)。 所以每遇到一个比栈顶元素大的数,就放进栈里,遇到比栈顶元素小的就二分查找前...
1、严格意义上,这个题和二分查找没啥特别大的关系,23333。 一起来看一个实例分析吧: 2、为什么数组d要是d[numsSize+1]? 原因很简单,为了保证下标同步。 3、数组d是单调递增的嘛? 看了LeetCode上的题解,感觉反证不如直接得来的快,d其实就是我们需要的最长子序列,因为是上升的,自然得是递增的。