力扣456. 132模式(数组记录最小,单调栈记录次小,枚举得到最大)

力扣456. 132模式(数组记录最小,单调栈记录次小,枚举得到最大)

https://leetcode-cn.com/problems/132-pattern/

一、暴力

132 模式的三元组下标 (i, j, k)(i,j,k),枚举其中的 22 个下标时间复杂度为 O(n^2)O(n2),很容易超出时间限制

class Solution {
public:
	bool find132pattern(vector<int>& nums) {
		int n = nums.size();
		vector<int> minval(n, 0);
		minval[0] = nums[0];
		for (int i = 1; i < n; i++)
		{
			minval[i] = min(minval[i - 1], nums[i - 1]);
		}
		for (int i = 0; i < n; i++)
		{
			cout << minval[i] << " ";
		}
		cout << endl;
		for (int j = 1; j < n - 1; j++)
		{
			for (int k = j + 1; k < n; k++)
			{
				if ((minval[j] < nums[k]) && (nums[k] < nums[j]))
				{
					return true;
				}
			}
		}
		return false;
	}
};

二、数组记录最小,单调栈记录次小,枚举得到最大

单调栈记录比元素大的值,或者是记录比元素次小、次次小的值。

思路

  • 遍历的位置 j 相当于 132 模式中的 3,即 nums[j] ;
  • 找到 3 左边的最小元素 为 1,即 nums[i] ;
  • 找到 3 右边的比 3 小的最大元素 为 2,即 nums[k] ;

在方法一的做法中,是使用暴力求解得到的 2,很显然时间复杂度比较高。我们想要的 2 其实满足两个条件:

  • 比 3 小;
  • 在 nums[j+1 .. N-1]nums[j+1..N−1] 区间的最大元素。

为了找到这样的元素,我们可以使用一个单调递减的「栈」。所谓「单调栈」就是栈中的元素都是依次递增或者递减的,从而方便我们能维护好数组的一个区间内的「最大值」「次大值」等等。

想要求比 3 小的最大元素,则需要一个单调递减的栈。这样的话,最大元素在栈底,次大元素在栈底的第二元素……

具体到本题的实现方式:

  • 求任何位置的左边最小的元素 nums[i] ,可以提前遍历一次而得到;
  • 使用「单调递减栈」,从右到左,把 nums[j]  入栈时,需要把栈里面比它小的元素全都 pop 出来,由于越往栈底越大,所以 pop 出的最后一个元素,就是比 3 小的最大元素 nums[k] 
  • 判断如果 nums[i] < nums[k] ,那就说明得到了一个 132 模式。

因为单调栈是建立在 3 的右边的,因此,我们使用从右向左遍历。

当我们遍历到一个位置 i 需要寻找数组中左边或者右边的所有数字和 nums[i] 的大小关系的题目,可以考虑一下单调栈

class Solution {
public:
	bool find132pattern(vector<int>& nums) {
		int n = nums.size();
		vector<int> minval(n, 0);
		minval[0] = nums[0];
		for (int i = 1; i < n; i++)
		{
			minval[i] = min(minval[i - 1], nums[i - 1]);
		}
		for (int i = 0; i < n; i++)
		{
			cout << minval[i] << " ";
		}
		cout << endl;
		stack<int>sta;
		sta.push(nums[n - 1]);
		for (int j = n - 2; j >= 1; j--)
		{
			int temp = INT_MIN;
			while (!sta.empty() && nums[j] > sta.top())
			{
				temp = sta.top();
				sta.pop();
			}
			sta.push(nums[j]);
			if (temp > minval[j])
			{
				return true;
			}
		}
		return false;
	}
};

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值