132 Pattern 132模式

给定一个整数序列: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].

思路:一开始以为这道题可以用两边扫描来做,Longest Mountain in Array和这道题类似,后面才发现这道题要满足:ai < ak < aj   也就是要满足第一个数小于第三个数,之前的方法也就用不了了,这道题有种比较笨的方法,就是按照题意顺序一个一个查找,但是这样的效率很低。下面介绍一个灰常巧妙的用stack来做的方法。。。(思路之巧根本想不出来。。。)

问题:搜索子序列(s1,s2,s3),使s1 <s3 <s2。

直觉:假设我们想找到一个带有s1 <s2 <s3的123序列,我们只需找到s3,然后是s2和s1。现在,如果我们想找到一个带有s1 <s3 <s2的132序列,我们需要切换搜索顺序。我们想首先找到s2,然后是s3,然后是s1。

检测:更准确地说,我们在搜索左侧有效的s1候选者时,跟踪每个有效(s2> s3)组合的s3的最大值。一旦我们遇到左边的任何数字小于我们到目前为止看到的最大s3,我们就知道我们找到了一个有效的序列,因为s1 <s3意味着s1 <s2。

算法:我们可以从任何一方开始,但是从右边开始可以一次扫描就做完。我们的想法是从最右边开始并搜索有效的(s2,s3)对,只需要记住最大的有效s3值,使用堆栈将有效用于此目的(堆里的所有值是s2,均大于s3)。如果左边有任何数字大于它,则数字成为s3的候选者。

正确性:当我们从右向左扫描时,我们可以轻松地跟踪到目前为止遇到的所有(s2,s3)候选者的最大s3值。因此,每当我们将nums [i]与区间nums [i + 1] ... nums [n-1]中s3的最大候选者进行比较时,我们实际上会问这样的问题:是否有任何132序列,其中s1 = nums [i]?因此,如果函数返回false,则必须没有132序列。

实现:

有一个堆栈,每次我们存储一个新号码时,我们首先会弹出小于该号码的所有号码。弹出的数字成为s3的候选者。
我们跟踪这样的s3的最大值(它始终是堆栈中最近弹出的数字)。
一旦我们遇到任何小于s3的数字,我们就知道我们找到了一个有效的序列,因为s1 <s3意味着s1 <s2。
RUNTIME:每个项目最多被推送一次,因此时间复杂度为O(n)。

例:
i = 6,nums = [9,11,8,9,10,7,9],S1候选= 9,S3候选=无,Stack =空
i = 5,nums = [9,11,8,9,10,7,9],S1候选= 7,S3候选=无,Stack = [9]
i = 4,nums = [9,11,8,9,10,7,9],S1候选= 10,S3候选=无,Stack = [9,7]
i = 3,nums = [9,11,8,9,10,7,9],S1候选= 9,S3候选= 9,Stack = [10]
i = 2,nums = [9,11,8,9,10,7,9],S1候选= 8,S3候选= 9,Stack = [10,9]我们有8 <9,序列(8,10) ,9)!

参见代码如下:

class Solution {
public:
    bool find132pattern(vector<int>& nums) {
	stack<int> s;
	int third = INT_MIN;
	for (int i = nums.size() - 1; i >= 0; i--) {
		if (nums[i] < third) return true;
		while (!s.empty() && nums[i] > s.top()) {
			third = s.top();
			s.pop();
		}
		s.push(nums[i]);
	}
	return false;        
    }
};

 

猜你喜欢

转载自blog.csdn.net/qq_26410101/article/details/81748574
132