题目:
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 = 6, nums = [ 9, 11, 8, 9, 10, 7, 9 ], S1
candidate = 9, S3 candidate = None, Stack = Empty
i = 5, nums = [ 9, 11, 8, 9, 10, 7,
9 ], S1 candidate = 7, S3
candidate = None, Stack = [9]
i = 4, nums = [ 9, 11, 8, 9, 10,
7, 9 ], S1 candidate = 10, S3
candidate = None, Stack = [9,7]
i = 3, nums = [ 9, 11, 8, 9,
10, 7, 9 ], S1 candidate = 9, S3
candidate = 9, Stack = [10]
i = 2, nums = [ 9, 11, 8,
9, 10, 7, 9 ], S1 candidate = 8, S3
candidate = 9, Stack = [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;
}
};
本文介绍了一种高效的算法来检查一个整数序列中是否存在132模式,即是否存在i < j < k且序列中的ai < ak < aj。通过从右向左扫描并使用栈来维护最大s3候选者的策略,该算法仅需O(n)的时间复杂度。

被折叠的 条评论
为什么被折叠?



