跳转至

456. 132 模式

原题链接

题目描述

给你一个整数数组 \(nums\) ,数组中共有 \(n\) 个整数。

132 模式的子序列 由三个整数 \(nums[i]\)\(nums[j]\)\(nums[k]\) 组成,并同时满足:\(i < j < k\)\(nums[i] < nums[k] < nums[j]\)

如果 \(nums\) 中存在 132 模式的子序列 ,返回 \(true\) ;否则,返回 \(false\)

示例 1:

1
2
3
输入:nums = [1,2,3,4]
输出:false
解释:序列中不存在 132 模式的子序列。

示例 2:

1
2
3
输入:nums = [3,1,4,2]
输出:true
解释:序列中有 1 个 132 模式的子序列: [1, 4, 2] 。

示例 3:

1
2
3
输入:nums = [-1,3,2,0]
输出:true
解释:序列中有 3 个 132 模式的的子序列:[-1, 3, 2]、[-1, 3, 0] 和 [-1, 2, 0] 。

提示:

  • \(n\) \(=\) \(nums.length\)
  • \(1\) \(≤\) \(n\) \(≤\) \(2 * 10^5\)
  • \(-10^9\) \(≤\) \(nums[i]\) \(≤\) \(10^9\)

算法与思路

(单调栈)   \(O(n)\)

我们可以来考虑把每个数当成 132 模式的子序列1 的情况,记为 \(a[i]\) ,当且仅当存在两个数 \(a[j], a[k]\),满足 \(i < j < k\)\(a[j] > a[k] > a[i]\) 时,132 模式的子序列 存在。

在满足以上 充要条件 中得出 \(a[j]\)\(a[k]\)单调递减 的。

在单调栈中,从栈底到栈顶的元素是严格单调递减的。当给定阈值 \(x\) 时,我们只需要不断地弹出栈顶的元素,直到栈为空或者 \(x\) 严格小于栈顶元素。此时我们再将 \(x\) 入栈,这样就维护了栈的单调性。

因此可以维护一个单调栈来判断当前 \(a[i]\) 是否满足条件。

  1. 维护 \(a[j], a[k]\) 的单调栈操作可以 从右往左 遍历数组,每次判断当前数是否 小于 \(a[k]\)
    • 为了方便起见,可以定义一个 \(right\) 来记录当前数为 \(a[i]\) 的情况下,\(a[k]\)最大值
    • 若满足条件,返回 \(true\)
    • 若不满足,继续进行下列操作。
  2. 如果栈顶元素 小于 当前数 \(a[i]\),弹出栈顶元素,直到栈顶元素 大于 当前数 \(a[i]\)
  3. 将当前数 \(a[i]\) 插入栈内,继续遍历下一个数,直到遍历完这个数组,返回 \(false\)
复杂度分析

时间复杂度:O(n)。枚举 \(i\) 的次数为 \(O(n)\),由于每一个元素最多被加入和弹出单调栈各一次,因此操作单调栈的时间复杂度一共为 \(O(n)\),总时间复杂度为 \(O(n)\)

空间复杂度:\(O(n)\),即为单调栈需要使用的空间。


代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class Solution {
public:
    bool find132pattern(vector<int>& nums) {
        int right = INT_MIN;    // 起初定义为最小值,保证单调性
        stack<int> s;
        for (int i = nums.size() - 1; i >= 0; i--) {
            if (nums[i] < right) return true;
            while (!s.empty() && s.top() < nums[i]) {
                right = max(right, s.top());
                s.pop();
            }
            s.push(nums[i]);
        }
        return false;
    }
};
回到页面顶部