题目描述

题目分析

我觉得这道题应该是我做过最难的中等题之一了,这是昨天的每日一题,但是昨天用nlogn的做法做出来以后在看题解,发现有些看不懂(觉得题解有点故弄玄虚)。然后今天中午又花了一点时间才搞懂,感觉从这道题里面学到一点东西。

刚拿到这道题的时候我没有什么思路,第一想法当然是n3n^3n3的暴力,但是显然是不行的,第二想法是,用线段树维护区间最大值,然后遍历12,这样的复杂度是n2lognn^2lognn2logn,虽然好了一点但仍然会超时。我自己没有想到枚举一个,然后通过数据结构求其他两个的思路,觉得这方面有点欠缺,即这种思路的转换,仿佛变量比较多就必须每一个都枚举才可以。

遍历3,用红黑树维护2

看到题解从左往右枚举3,然后用一个变量保存1(左边的最小值),用一个红黑树(使用set)保存右边所有的值,在里面查找比1大比3小的数。这样的做法很符合直觉。
我用这样的思路很快写了一个和题解差不多的代码:

O(nlogn)代码

class Solution {public:bool find132pattern(vector<int>& nums) {using vector_size = vector<int>::size_type;vector_size n = nums.size();if (n < 3) return false;int left_min = nums[0];multiset<int> right_all(nums.begin() + 2, nums.end());for (vector_size i = 1; i < n - 1; ++i) {if (left_min < nums[i]) {auto iter = right_all.upper_bound(left_min);if (iter != right_all.end() && *iter < nums[i]) {return true;}}left_min = min(left_min, nums[i]);right_all.erase(right_all.find(nums[i + 1]));}return false;}
};

红黑树的查找和删除都是logn的,真不错。

其他思路都统统使用了单调栈,其实单调栈本身的非常简单,就是一个栈,里面是有序的,如果一个新加入的元素破坏了顺序,就弹出,直到不破坏为止,再入栈。

遍历1,用单调栈维护32

这道题的神奇之处在于用了一个递减的单调栈,并用一个变量保存所有出栈元素的最大值,因为入栈、出栈操作的先后顺序导致这个出栈元素的最大值肯定比栈中某个元素小而且在其前面,因为是那个元素将它出栈的,而这样就得到了32,我们只要遍历到比2小的1即可。这种方法的复杂度应该是最低的。

O(n)代码

class Solution {public:bool find132pattern(vector<int>& nums) {int n = nums.size();if (n < 3) return false;stack<int> stk;     //单调栈int max_pop = INT_MIN;        //弹出的元素的最大值for (int i = n - 1; i >= 0; --i) {if (max_pop != INT_MIN) {if (nums[i] < max_pop) return true;}while (!stk.empty() && nums[i] > stk.top()) {max_pop = max(max_pop, stk.top());stk.pop();}stk.push(nums[i]);}return false;}
};

刚才习惯性地使用vector<int>::size_type类型,但是循环的时候却RE,这是因为size_type类型是一个unsigned类型,在---1的时候会变成一个非常大的数字导致死循环。应该尽量还是用int才好。

遍历3,用单调栈维护2,用前缀数组维护1

虽然同样是使用单调栈解决问题,但是用单调栈维护2的思路则和上面完全不同。我在看题解的时候一度非常迷惑,但是想明白原理以后才发现原来两者之间没有什么关系。

上面已经提到了,上面的解法的精髓在于维护了所有弹出元素的最大值,通过入栈、出栈的逻辑顺序得到了数据的物理顺序。但是现在这种解法则是完全不一样的角度。

我们用一个前缀数组处理出任意位置左边的最小值,得到1,用单调栈维护右边的比本身3小的最大值,得到2,通过判断12的大小来决定是否存在132序列。

问题的难点在于如何用单调栈维护右边比当前遍历到的3小的最大值,做法如下:将把当前值插入到单调栈中弹出的数据的最大值作为2

我认为难以理解的地方在于,把一些比较小的数组弹出了,怎么能够保证后面不会用到这些数字呢?

想要理解,可以用一个简单的数学归纳:

  1. 初始的时候栈中是有元素的
  2. 新插入的当前元素可能没有进行弹出操作,这意味着右边全都是比当前值大的数字
  3. 当第一次插入x发生弹出时,我们保存了弹出元素的最大值right_max,并且和其左边最小值left_min进行比较,如果right_max>left_min,则出现132序列,如果没有出现,则意味着x左边全部元素大于等于right_max,也就是说right_max以及其他这次弹出的数据无论如何都不会成为2了,因此可以丢弃。

如果理解了上面的话,代码就比较简单了:

O(nlogn)代码

class Solution {public:bool find132pattern(vector<int>& nums) {int n = nums.size();if (n < 3) return false;stack<int> stk;     //单调栈维护2int max_pop;        //一次pop的最大值vector<int> left_min;left_min.reserve(nums.size());left_min.push_back(INT_MAX);for (int i = 1; i <n; ++i) {left_min[i] = min(left_min[i - 1], nums[i - 1]);}stk.push(nums[n - 1]);for (int i = n - 2; i >= 0; --i) {max_pop = INT_MIN;while (!stk.empty() && nums[i] > stk.top()) {max_pop = max(max_pop, stk.top());stk.pop();}if (left_min[i] < max_pop) return true;stk.push(nums[i]);}return false;}
};

时间复杂度应该是比第二种解法要高一个O(n)

每日一题:leetcode456.132模式相关推荐

  1. [Leetcode456]132模式 - 单调栈

    [Leetcode456]132模式 - 单调栈 给你一个整数数组 nums ,数组中共有 n 个整数.132 模式的子序列 由三个整数 nums[i].nums[j] 和 nums[k] 组成,并同 ...

  2. 安卓 每日一题 2019年9-12月问题及答案

    最新 文章连接,本文不再同步 安卓 每日一题 2019年9-12月问题及答案 文章目录 安卓 每日一题 2019年9-12月问题及答案 安卓2019年09月每日一题 安卓2019年10月每日一题 安卓 ...

  3. js自动触发onclick_每日一题JS中最基本的this情况分析

    关注"前端学苑" ,坚持每天进步一点点 「~this情况分析 ~」 每日一题,希望让爱学习.思考的前端技术伙伴在一起学习.复盘.成长. 基础知识要夯实,原理源码要深入,深度广度要扩 ...

  4. 易错丨Oracle 每日一题系列合集

    在墨天轮平台有个[数据库每日一题]栏目:www.modb.pro/test(复制到浏览器或者点击"阅读原文"可直达,每日一题),均是由数据库行业的专家亲自出题,墨天轮审核后发布的一 ...

  5. leetcode 456. 132 Pattern 132模式 题解(栈)

    [例子1]132 Pattern https://leetcode.com/problems/132-pattern/description/ Given a sequence of n intege ...

  6. Java实习生常规技术面试题每日十题Java基础(七)

    目录 1. Java设计模式有哪些? 2.GC是什么?为什么要有GC? 3. Java中是如何支持正则表达式. 4.比较一下Java和JavaSciprt. 5.Math.round(11.5) 等于 ...

  7. Java实习生常规技术面试题每日十题Java基础(六)

    目录 1.在Java语言,怎么理解goto. 2.请描述一下Java 5有哪些新特性? 3.Java 6新特性有哪些. 4.Java 7 新特性有哪些. 5.Java 8 新特性有哪些. 6.描述Ja ...

  8. 安卓 每日一题 2020年3月问题及答案

    Android 3月2日题: onMeasure是干什么的? 答案: onMeasure方法主要是用于度量ViewGroup的子view的大小同时确定和保存自己ViewGroup的大小,将xml中的布 ...

  9. 安卓 每日一题 2020年5-6月问题及答案

    最新 文章连接,本文不再同步 Android5月7日题: 在使用 HashMap 的时候,用 String 做 key 有什么好处? 参考答案: HashMap 内部实现是通过 key 的 hashc ...

最新文章

  1. 矩阵快速幂+构造方法
  2. C# WebBrowser document.execCommand()解析
  3. python之递归锁【Rlock】
  4. 统计之都统计分析和R语言方面的图书
  5. C运行时库和标准C++库
  6. qt交叉编译环境搭建方法
  7. 关于Linux网卡调优之:RPS (Receive Packet Steering)
  8. YbSoftwareFactory 代码生成插件【九】:基于JQuery、WebApi的ASP.NET MVC插件的代码生成项目主要技术解析...
  9. android room_Android Room –待办事项清单应用程序
  10. 利用MessageUI发送邮件
  11. yum mysql 设置密码_Linux下的 Mysql 8.0 yum 安装 并修改密码
  12. 软件测试中的测试文档
  13. 从零开始实现Unity光照模型_02_为Shader添加简单的多光源支持_技术美术基础学习记录
  14. 障碍期权定价 python_python障碍式期权定价公式
  15. canvas-八卦图和时钟实现
  16. 内网渗透-信息收集整合
  17. 惯性传感器实现全身姿态检测
  18. 离谱的 CSS!从表盘刻度到剪纸艺术
  19. java匿名内部类,什么是匿名内部类,如何定义匿名内部类,如何使用匿名内部类?
  20. 大数据基础--学好大数据必看的文章

热门文章

  1. django用户认证系统——登录4
  2. C语言结构体及函数传递数组參数演示样例
  3. 【Linux学习篇】This virtual machine is configured for 64-bit guest operating systems.……
  4. Adroid学习之 从源码角度分析-禁止使用回退按钮方案
  5. Java 性能优化实战记录(2)---句柄泄漏和监控
  6. java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory 解决方案
  7. KingPaper初探ThinkPHP3.1.2之扩展函数库和类库的使用(四)
  8. 独家:Havok 发布新的 AI 中间件
  9. 一段简单的html 5 音频,5个用于处理HTML5音频的库和API
  10. php ci model条件查询,Laravel关系模型指定条件查询方法