久违的题解,大概近一周的时间没有写了。
题目说明
给你一个整数数组 nums ,数组中共有 n 个整数。132 模式的子序列 由三个整数 nums[i]、nums[j] 和 nums[k] 组成,并同时满足:i < j < k 和 nums[i] < nums[k] < nums[j] 。
如果 nums 中存在 132 模式的子序列 ,返回 true ;否则,返回 false 。
进阶:很容易想到时间复杂度为 O(n^2) 的解决方案,你可以设计一个时间复杂度为 O(n logn) 或 O(n) 的解决方案吗?
输入:nums = [1,2,3,4]
输出:false
解释:序列中不存在 132 模式的子序列。
输入:nums = [-1,3,2,0]
输出:true
解释:序列中有 3 个 132 模式的的子序列:[-1, 3, 2]、[-1, 3, 0] 和 [-1, 2, 0] 。
解答
我承认这题我不会,只能去看题解了,像我这种菜鸡,题解也看了很久才看懂。想讲出来真的很难。
这题采用的是单调栈的解法,与一般的单调栈问题不同,栈里的元素不再是问题的解,而是通过栈顶元素进行求解。
问题要求判断是否存在 1 - 3 - 2 类型的子数组。
想了很长时间,其实问题的关键在于,我们想让“2”尽可能的大,这样在遍历的过程中对“1”的要求就变小了。因此从后向前遍历数组,这样可以对“2”的情况进行遍历,寻找符合条件的“2”。同时我们用一个变量maxn来记录“2”的可能的最大值。
在遍历时,用栈来对数据进行记录,假如栈中的数据均比maxn大,并且栈顶元素比maxn晚出现同时遍历到的数据比maxn小,那么就出现1-3-2模式。
我们需要记住一点,那就是“3”是有可能变成“2”的,前提条件是在它之前有比它大的数。因此,我们的思路是用栈来记录遍历的数据,前提条件是它要比maxn大。我们在从后向前遍历的时候,有可能在后面有一个比较大的数可以作为“2”,只要在前面有一个比它大的数。那么此时这个数其实就没有必要存储了,因为无用了,我们已经判断过了。就比如,假如一个子序列是[4,2,1,3]。那么“3”就是4,“2”就是3,无需考虑“2”是1或2的情况。
所以栈存储的数据其实是有可能成为“2”但是到目前为止它前面的数还没有比它大的,如果有比它大的,那么数据就可以出栈了。这样其实很清楚了,栈是单调栈,也就是从栈底到栈顶,数据依次减小。每当遍历到一个数据时,在它之后的比它小的数我们就不需要了,只需要知道比它小的最大的数是多少,方便我们找出“1”。所以,每当遍历到一个数,如果它比maxn小,那么就出现1-3-2模式,因为栈顶元素一定比maxn大;将栈中比它小的数出栈;同时更新maxn。
如果到最后还没有这种情况,那么就不存在1-3-2的子序列。
具体代码如下所示:
class Solution {
public:
bool find132pattern(vector<int>& nums) {
int len = nums.size();
stack<int> st;
int maxn = INT_MIN;
st.push(nums[len - 1]);
for(int i = len - 2; i >= 0; i--){
if(nums[i] < maxn){
return true;
}
while(!st.empty() && nums[i] > st.top()){
maxn = st.top();
st.pop();
}
if(nums[i] > maxn){
st.push(nums[i]);
}
}
return false;
}
};