题目:456. 132模式
难度: 中等
题目:
给你一个整数数组 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) 的解决方案吗?
示例1
输入:nums = [1,2,3,4]
输出:false
解释:序列中不存在 132 模式的子序列。
示例2
输入:nums = [3,1,4,2]
输出:true
解释:序列中有 1 个 132 模式的子序列: [1, 4, 2] 。
示例3
输入:nums = [-1,3,2,0]
输出:true
解释:序列中有 3 个 132 模式的的子序列:[-1, 3, 2]、[-1, 3, 0] 和 [-1, 2, 0] 。
提示
- n == nums.length
- 1 <= n <= 104
- -109 <= nums[i] <= 109
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/132-pattern
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
(1)暴力破解
在一系列nums中找到132模式的数,也就是说:1是最小的,3是中间的也是最大的,2比1大但比3小。如果直接强行解,那么循环3次,分别遍历1、3、2,恭喜你:时间复杂度O(n^3),直接超时。
当然如果我们控制一个变量,遍历两个数,还是可以做到O(n^2),也算暴力破解了。比较好的想法是控制3,先遍历3,也就是中间的最大的数。那么1必然在3左边的且小于3小于2,那么1可以取3左边最小的就肯定不会错了。而后再遍历2,在3的最左边,只要3>2且2>1,那么肯定3>2>1。
(2)单调栈
可以用一个栈存储3,一个变量max2记录2的最大值,从尾部到头遍历1,直到找到小于max2的数,就找到132模式数。实现单调栈时,如果当前元素大于栈顶,不断弹出栈中元素,并记录小于当前元素的最大值,然后再讲当前元素压栈,这时就保证了3>2,只要在找到2>1就找到132模式数了。
解题代码
(1)暴力破解
class Solution {
public:
bool find132pattern(vector<int>& nums) {
int n = nums.size();
int num1 = nums[0];//132模式中的1,即最小的数
for(int i = 1; i < n - 1; i++)//该处遍历3,即中间的数,也是最大的数
{
for(int j = n - 1;j > i; j--)
{
if(nums[j] > num1 && nums[i] > nums[j])// 3>2 2>1 则:2 > 3 > 1
return true;
}
num1 = num1 < nums[i] ? num1 : nums[i];
}
return false;
}
};
(2)单调栈
class Solution {
public:
bool find132pattern(vector<int>& nums) {
stack<int> stk;//单调栈,存入的数据为3
int max2 = INT_MIN;//2的最大值,越大越容易找到1
int n = nums.size();
stk.push(nums[n - 1]);//压入最后一个数,从尾到头遍历
for(int i = n - 1; i >= 0; i--)//此处遍历1
{
if(nums[i] < max2)//如果2>1,之前已经满足3>2了
{
return true;
}
while(!stk.empty() && nums[i] > stk.top())
{
max2 = stk.top();//存储2的最大值
stk.pop();
}
if(nums[i] > max2)
stk.push(nums[i]);
}
return false;
}
};
解题感悟
该题难度有点大,特别是单调栈,不看题解写不出。。。写完单调栈,倒是有些许感悟:首先,要有贪心的思想,毕竟只是找到是否有132模式的数而非找到所有的数,因此要大胆。接着,很明显3个变量,比较难控制。但是用一个栈加一个变量,就实现了一次遍历保证3>2,这时候只要2>1即可,因此再在下次进入时判断就完成了。还有就是从后往前遍历,因为3和2是最大和次大,比较好维护。