LeetCode 456.132模式
原题链接: LeetCode-456.132模式 Medium
题意:
给你一个整数数组 nums
,数组中共有 n
个整数。132 模式的子序列 由三个整数 nums[i]
、nums[j]
和 nums[k]
组成,并同时满足:i < j < k 和 nums[i] < nums[k] < nums[j]
。如果 nums
中存在 132 模式的子序列 ,返回 true
;否则,返回 false
。
解题思路:
- 比较容易想到的一个思路是枚举每个i,j,k,并判断是否有i < j < k并且nums[i] < nums[k] < nums[j]这种情况,时间复杂度O(n^3)会超时,我们需要尝试找到更优的思路。
- 回到题目中,我们知道132模式是在nums数组中存在一个长度为为3的子序列(不破化它们原有的位置关系),我们可以尝试枚举该模式下的"3”(即位置处于中间,值是严格大于前后两个元素的值的元素nums[j]),我们希望每一个"3"可以找到一个在其右边并且值比它小的元素nums[k],也就是“2”,即j < k 且 nums[j] > nums[k],假设我们找到了满足上述的“2”,我们只需要找到一个满足条件的“1”,即满足 i < j 且nums[i] < num[j],至此我们得到了 i < j < k 且 nums[i] < nums[k] < nums[j]。
子序列,又称子数列,在数学中,某个序列的子序列是从最初序列通过去除某些元素但不破坏余下元素的相对位置(在前或在后)而形成的新序列。
抽象过程:
-
我们有了上面的思路后,需要用抽象这个过程。
-
我们找到满足条件的num[j]后,需要找到比nums[j]小的nums[i],且i < j,由于随着解题的进行索引是递减的,所以我们需要从右往左遍历整个数组,从前往后遍历每一个元素nums[k],我们需要将其与接下来遍历到的nums[j]作比较,于是我们需要需要一个栈来存下遍历到的nums[k],如果遍历到的元素比栈顶元素大即 stack.top() < nums[j],这个时候我们用变量k存下栈顶的元素,其作为”2“,并将其出栈,往前遍历时我们只要遇到当前元素比存下的”2“小就说明存在132模式。
在整篇大部分提到的nums[i]、nums[j]、nums[k]都是我们每一次遍历到的同一个元素,只是在当前情况下我们对它的状态做一个假设,来达到我们解题的目的,请大家结合分析来理解。
注意:在遍历过程中我们每次更新nums[j]时,需要保存其最大值。
- 第一是由于:初始化时的k应当无穷小(由于遍历到的nums[i] < k这种小于关系我们可以得到是存在132模式的,针对这个小于关系我们需要在未找到nums[j]的情况下,能够保证num[i] >= k是一定满足的,以至于不会错判)。
- 第二是由于:保留最大值在一定情况下能够减少我们对nums[i]的限制;同时也是上个原因的必要条件(只有这样才能对初始的k进行更新)。
C代码:
bool find132pattern(int* nums, int numsSize){
int stack[200000], top = 0;
int k = INT_MIN;
for(int i = numsSize - 1; i >= 0; i--)
{
if(nums[i] < k) return true;
while(top && stack[top - 1] < nums[i])
{
k = fmax(k, stack[--top]);
}
stack[top++] = nums[i];
}
return false;
}