Given a sequence of n integers a1, a2, ..., an, a 132 pattern is a subsequence ai, aj, ak such that i < j < k and ai < ak < aj. Design an algorithm that takes a list of n numbers as input and checks whether there is a 132 pattern in the list.html
Note: n will be less than 15,000.java
Example 1:數組
Input: [1, 2, 3, 4] Output: False Explanation: There is no 132 pattern in the sequence.
Example 2:less
Input: [3, 1, 4, 2] Output: True Explanation: There is a 132 pattern in the sequence: [1, 4, 2].
Example 3:post
Input: [-1, 3, 2, 0] Output: True Explanation: There are three 132 patterns in the sequence: [-1, 3, 2], [-1, 3, 0] and [-1, 2, 0].
這道題給咱們了一個數組,讓咱們找到 132 的模式,就是第一個數小於第二第三個數,且第三個數小於第二個數。固然最直接最暴力的方法,就是遍歷全部的三個數字的組合,而後驗證是否知足這個規律。得莫,OJ 說打妹。那麼就只能想辦法去優化了,因爲暴力搜索的時間複雜度是三次方,在以前的 3Sum 那道題中,咱們也有把立方的複雜度減小到平方的複雜度,至關於降了一維(降維打擊麼?),其實就是先固定一個數字,而後去遍歷另外兩個數字。咱們先肯定哪一個數字呢,固然是最小的那個啦,咱們維護一個變量 mn,初始化爲整型最大值,而後在遍歷數字的時候,每次用當前數字來更新 mn,而後咱們判斷,若 mn 爲當前數字就跳過,由於須要找到數字j的位置,數字j是大於數字i的,mn 表示的就是數字i。這樣數字i和數字j都肯定了以後,就要來遍歷數字k了,範圍是從數組的最後一個位置到數字j之間,只要中間的任何一個數字知足題目要求的關係,就直接返回 true 便可,參見代碼以下:優化
解法一:url
class Solution { public: bool find132pattern(vector<int>& nums) { int n = nums.size(), mn = INT_MAX; for (int j = 0; j < n; ++j) { mn = min(mn, nums[j]); if (mn == nums[j]) continue; for (int k = n - 1; k > j; --k) { if (mn < nums[k] && nums[j] > nums[k]) return true; } } return false; } };
那麼咱們就按順序來找這三個數,首先咱們來找第一個數,這個數須要最小,那麼咱們若是發現當前數字大於等於後面一個數字,咱們就往下繼續遍歷,直到當前數字小於下一個數字中止。而後咱們找第二個數字,這個數字須要最大,那麼若是咱們發現當前數字小於等於下一個數字就繼續遍歷,直到當前數字大雨下一個數字中止。最後就找第三個數字,咱們驗證這個數字是否在以前兩個數字的中間,若是沒有找到,咱們就從第二個數字的後面一個位置繼續開始從新找這三個數字,參見代碼以下:spa
class Solution { public: bool find132pattern(vector<int>& nums) {int n = nums.size(), i = 0, j = 0, k = 0; while (i < n) { while (i < n - 1 && nums[i] >= nums[i + 1]) ++i; j = i + 1; while (j < n - 1 && nums[j] <= nums[j + 1]) ++j; k = j + 1; while (k < n) { if (nums[k] > nums[i] && nums[k] < nums[j]) return true; ++k; } i = j + 1; } return false; } };
下面這種方法利用單調棧來作,既簡潔又高效,關於單調棧能夠參見博主以前的一篇文章 LeetCode Monotonous Stack Summary 單調棧小結。思路是咱們維護一個棧和一個變量 third,其中 third 就是第三個數字,也是 pattern 132 中的2,初始化爲整型最小值,棧裏面按順序放全部大於 third 的數字,也是 pattern 132 中的3,那麼咱們在遍歷的時候,若是當前數字小於 third,即 pattern 132 中的1找到了,咱們直接返回 true 便可,由於已經找到了,注意咱們應該從後往前遍歷數組。若是當前數字大於棧頂元素,那麼咱們將棧頂數字取出,賦值給 third,而後將該數字壓入棧,這樣保證了棧裏的元素仍然都是大於 third 的,咱們想要的順序依舊存在,進一步來講,棧裏存放的都是能夠維持座標 second > third 的 second 值,其中的任何一個值都是大於當前的 third 值,若是有更大的值進來,那就等於造成了一個更優的 second > third 的這樣一個組合,而且這時彈出的 third 值比之前的 third 值更大,爲何要保證 third 值更大,由於這樣才能夠更容易的知足當前的值 first 比 third 值小這個條件,舉個例子來講吧,好比 [2, 4, 2, 3, 5],因爲是從後往前遍歷,因此後三個數都不會進入 while 循環,那麼棧中的數字爲 5, 3, 2(其中2爲棧頂元素),此時 third 仍是整型最小,那麼當遍歷到4的時候,終於4大於棧頂元素2了,那麼 third 賦值爲2,且2出棧。此時繼續 while 循環,由於4仍是大於新棧頂元素3,此時 third 賦值爲3,且3出棧。如今棧頂元素是5,那麼 while 循環結束,將4壓入棧。下一個數字2,小於 third,則找到符合要求的序列 [2, 4, 3],參見代碼以下:code
解法三:htm
class Solution { public: bool find132pattern(vector<int>& nums) { int third = INT_MIN; stack<int> st; for (int i = nums.size() - 1; i >= 0; --i) { if (nums[i] < third) return true; while (!st.empty() && nums[i] > st.top()) { third = st.top(); st.pop(); } st.push(nums[i]); } return false; } };
討論:這道題的一個很好的 Follow up 就是求出全部 132 模式的數組,那麼解法二和解法三這種想要快速來驗證是否存在 132 模式的方法就不太適合,而解法一就比較適合了,咱們是須要在找到的時候不直接 return,而是將 mn,數字j,和數字k,放到一個數組裏,而後加入結果 res 中,試了題目中的例子3,是能夠正確的返回那三個結果的,別的也沒怎麼試過,感受應該是正確的。
參考資料:
https://leetcode.com/problems/132-pattern/
https://leetcode.com/problems/132-pattern/discuss/94135/c_ac