题目
给定一个整数序列:a1, a2, …, an,一个132模式的子序列 ai, aj, ak 被定义为:当 i < j < k 时,ai < ak < aj。设计一个算法,当给定有 n 个数字的序列时,验证这个序列中是否含有132模式的子序列。
注意:n 的值小于15000。
示例1:
输入: [1, 2, 3, 4]
输出: False
解释: 序列中不存在132模式的子序列。
示例2:
输入: [3, 1, 4, 2]
输出: True
解释: 序列中有 1 个132模式的子序列: [1, 4, 2].
示例3:
输入: [-1, 3, 2, 0]
输出: True
解释: 序列中有 3 个132模式的的子序列: [-1, 3, 2], [-1, 3, 0] 和 [-1, 2, 0].
题解
首先,考虑边界条件:如果数组中的个数小于3个,那么不可能出现132模式,直接返回False。
其次,这道题的暴力解法便是穷举给定数组所能构成的所有三元组,然后验证每一个三元组是否满足132模式,如果找到一个三元组满足条件,则返回True,否则返回False。穷举法的时间复杂度为O(N^3)。
接下来讲一下这道题比较机智的做法。首先规定一下术语,我们把132模式中最大的数叫做大数(也就是3的位置),最小的数叫做小数(也就是1的位置),剩下2的位置我们称为次大数。其次规定一下算法中使用到的变量:一个变量third用于记录次大数,一个栈stack用于记录所有可能的大数,并且stack中的数和次大数都要尽可能的大(也就是stack中的数要在已知数中尽量大,而次大数要仅次于stack中的最小数)。
规定完成之后,我们从后往前遍历整个数组(假设有一个指针从后往前指过每一个数):
1)如果当前(指针指的)数比third小,我们有当前数、stack中栈顶元素和third组成132模式,目标达成,返回True;
2)如果当前数比stack栈顶元素要大,说明stack中有些数已经过时了,需要退出栈顶元素,继续比较直到栈顶元素大于当前数,将当前数入栈同时令third等于最后一次pop出的数。(实际上,stack栈记录了已经遍历的数中从大到小排列,而third则是已遍历数中除去stack栈中元素的最大值,即遵循了次大数尽可能大的规定。)
3)若当前数不符合上述两个条件,也就是当前数没有third小,但是也没有stack栈顶元素大,那么他有当次大数(third)的潜质,我们把当前数放入stack栈中。
整个数组遍历完成后,若没有找到符合条件的132模式数组(即从未return过),则该数组中不存在132模式的数组,返回False。
注:之所以使用栈存储可能的大数,是为了保证大数一定在次大数的左侧。(靠左的数后入栈,也就越靠栈顶)
Python代码
class Solution(object):
def find132pattern(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
if len(nums)<=2:
return False
third = float('-inf')
stack = []
for i in range(len(nums)-1,-1,-1):
if nums[i]<third:
return True
else:
while stack and stack[-1] < nums[i]:
third = stack.pop()
stack.append(nums[i])
return False