[Leetcode] 456. 132 Pattern 解题报告

本文介绍了一种高效的算法来检查一个整数序列中是否存在132模式,即是否存在i < j < k且序列中的ai < ak < aj。通过从右向左扫描并使用栈来维护最大s3候选者的策略,该算法仅需O(n)的时间复杂度。

题目

Given a sequence of n integers a1, a2, ..., an, a 132 pattern is a subsequence ai, aj, ak such that i < j < k and ai < ak < aj. Design an algorithm that takes a list of n numbers as input and checks whether there is a 132 pattern in the list.

Note: n will be less than 15,000.

Example 1:

Input: [1, 2, 3, 4]

Output: False

Explanation: There is no 132 pattern in the sequence.

Example 2:

Input: [3, 1, 4, 2]

Output: True

Explanation: There is a 132 pattern in the sequence: [1, 4, 2].

Example 3:

Input: [-1, 3, 2, 0]

Output: True

Explanation: There are three 132 patterns in the sequence: [-1, 3, 2], [-1, 3, 0] and [-1, 2, 0].

思路

这道题目暴力法当然就是三重循环了,时间复杂度O(n^3),肯定过不了大数据测试。我看到最巧妙的代码仅仅需要遍历一遍,所以时间复杂度是O(n)。下面我们仔细分析。

假设我们要找到一个123序列,即s1 < s2 < s3,那么我们只需要依次找到s3,s2和s1即可。现在我们需要找到一个132序列,其中s1 < s3 < s2,我们就需要交换一下搜索顺序:首先找到s2,然后再找s3,最后找s1。更准确地讲,我们在搜索s1的过程中,记录下合法(s2 > s3)对子中s3的最大值。一旦我们在左侧发现一个小于最大s3的s1,则就可以返回了,这是因为s1 < s3可以推导出s1 < s2。

我们既可以从左到右扫描,也可以从右到左扫描,但是从右到左扫描仅仅需要扫描一遍。思路是:从右到左开始搜索合法的(s2, s3)对子。我们只需要记录下来最大的s3,而使用栈这种数据结构可以高效地达到这个目的。如果在某个数的左侧存在一大大于它的数,它就是s3的合法候选者。

由于我们是从右到左扫描的,所以我们可以容易地维护合法(s2, s3)对子中最大的s3的值。因此,每次我们比较nums[i]与区间nums[i + 1]...nums[n-1]的最大s3候选者,我们就可以问一个问题:是否存在以s1 = nums[i]为开头的132序列?因此,如果函数返回false,那么一定就没有132序列。这就证明了算法的正确性。

实现步骤如下:

1)定义一个栈,每次当我们存储一个新数的时候,我们首先弹出里面所有比它小的数字。而弹出的这些数就会成为s3的有效候选者。

2)我们维护s3的最大候选者(它一定是从栈中最后一个被弹出的数字);

3)一旦我们遇到一个比s3小的数,就说明我们找到了合法的序列s1 < s3。由于s2 > s3,所以一定可以推导出s1 < s2。

运行时间分析:由于每个数字最多入栈和出栈各一次,所以整个时间复杂度是O(n)。

对于序列[9, 11, 8, 9, 10, 7, 9],整个代码的运行过程如下:

i = 6nums = [ 9, 11, 8, 9, 10, 7, 9 ], S1 candidate = 9S3 candidate = NoneStack = Empty
i = 5nums = [ 9, 11, 8, 9, 10, 7, 9 ], S1 candidate = 7S3 candidate = NoneStack = [9]
i = 4nums = [ 9, 11, 8, 9, 10, 7, 9 ], S1 candidate = 10S3 candidate = NoneStack = [9,7]
i = 3nums = [ 9, 11, 8, 9, 10, 7, 9 ], S1 candidate = 9S3 candidate = 9Stack = [10]
i = 2nums = [ 9, 11, 8, 9, 10, 7, 9 ], S1 candidate = 8S3 candidate = 9Stack = [10,9] We have 8<9, sequence (8,10,9) found!

代码

class Solution {
public:
    bool find132pattern(vector<int>& nums) {
        if (nums.size() < 3) {
            return false;
        }
        int s3 = INT_MIN;
        stack<int> st;
        for( int i = nums.size() - 1; i >= 0; --i){
            if( nums[i] < s3 ) {
                return true;
            }
            else {	// nums[i] >= s3
                while( !st.empty() && nums[i] > st.top()) {
                    s3 = st.top();
                    st.pop();
                }
            }
            st.push(nums[i]);
        }
        return false;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值