力扣456. 132 模式(单调递减栈)

456. 132 模式

给你一个整数数组 nums ,数组中共有 n 个整数。132 模式的子序列 由三个整数 nums[i]、nums[j] 和 nums[k] 组成,并同时满足:i < j < k 和 nums[i] < nums[k] < nums[j] 。

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

进阶:很容易想到时间复杂度为 O(n^2) 的解决方案,你可以设计一个时间复杂度为 O(n logn) 或 O(n) 的解决方案吗?

示例 1:

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

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

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

提示:

n == nums.length
1 <= n <= 104
-109 <= nums[i] <= 109

题解:

首先我们最直白的想法自然是三层for循环,但是这样明显会超时,所以我们需要缩减for循环的嵌套。

方法一:两层for循环遍历

由“132”模式可知,我们中间的数大于左边的数,且其系数是要大于左边的数的,因此为了缩减一个for循环,我们可以将“132”中的一个数先定死,然后两层for即可解决问题。
因此我们可以制造一个min数组,其min[i]表达的意思为位于nums[i]左边的最小数,这样即可将每一个nums[i]对应的“132”模式中的“1”给确定。

代码:

int Min(int x,int y)
{
    
    
    return x<y?x:y;
}
bool find132pattern(int* nums, int numsSize){
    
    
    int min[numsSize];
    min[0] = nums[0];
    for(int i=1;i<numsSize;i++)
    {
    
    
        min[i] = Min(nums[i],min[i-1]); 
    }
    for(int j=0;j<numsSize;j++)
    {
    
    
        for(int k=j+1;k<numsSize;k++)//注意k为j的右边的数
        {
    
    
            if(nums[k]<nums[j]&&nums[k]>min[j])//min用j,因为min下标为题目的i,所以为在j的前面
            {
    
    
                return 1;
            }
        }
    }
    return 0;
}

方法二:单调递减栈

读题可以了解到和栈是有关系的,所以我们可以从栈的角度来思考一下。

首先如果使用栈时,我们大多数情况下只能维护一个单调递增的栈或者一个单调递减的栈,而对于“132”模式这种有增有减的序列不好维护,因此我们可以同方法一一样,先定死“132”中的“1”,因此这时候就变成维护一个单调递减的栈了(即下标增大但是元素大小减小)。所以此时得知符合先进后出的思想,因此我们使用栈来解决该问题。

而又因为此为单调递减栈,如果正序遍历nums数组,我们就需要考虑先从栈尾填入还是先从栈顶填入,因此我们不妨根据“单调递减”的特性,直接倒序遍历nums数组,这样的话从栈顶填入元素发现刚好满足单调递减栈的特性。

因此在进行操作时,当栈为空则直接入栈;
若栈不为空,我们可以进行判断:
栈外元素是否大于栈顶元素
若大于,则根据单调递减栈的定义,我们需要将栈顶元素出栈,将此元素入栈,而此时发现被我们“抛弃”掉的原栈顶元素其也是有可能满足“132”模式中的“2”部分,但由于我们没有进行所谓的“栈顶栈外交换”等麻烦的操作,而是直接让其出栈,因此我们需要设置一个变量来存储被“抛弃”的,出栈的元素,并每次更新出栈元素的最大值

如果不大于,需要看栈是否满,如果没有满的条件下,则其k,也就是“132”中的2,必定仍为INT_MIN,所以必定不满足k>min[i],即不满足“132”中的2大于1.
若栈已满,需要看栈内的第二个元素是否大于min[i],如果大于直接输出,不大于的话即代表“132”中的2还没有没找到,所以继续遍历寻找“2”。

代码:

int Min(int x,int y)
{
    
    
    return x<y?x:y;
}
int max(int x,int y)
{
    
    
    return x>y?x:y;
}
bool find132pattern(int* nums, int numsSize){
    
    
    int*res = (int*)malloc(sizeof(int)*numsSize);
    int top = 0;
    int min[numsSize];
    min[0] = nums[0];
    for(int i=1;i<numsSize;i++)
    {
    
    
        min[i] = Min(nums[i],min[i-1]);//这里其实也有一点动态规划的思想
    }
    int k = INT_MIN;
    for(int i=numsSize-1;i>=0;i--)
    {
    
    
        while(top>0&&res[top-1]<nums[i])//满足出栈
        {
    
    
            k = max(k,res[top-1]);
            top--;
        }
        if(k>min[i])
        {
    
    
            return 1;
        }
        res[top++] = nums[i];
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xiangguang_fight/article/details/115248913
132