-
前言
传送门看讨论区和题解区清一色都是双指针
确实这道题双指针时间空间最优
但还是想分享一下对于贪心的一些理解,和从另一种角度出发的算法
-
对题目的理解
很容易可以得到这道题的体积公式:
V m a x = h m i n × ( △ p ) △ p = p m a x − p m i n \begin{aligned} V_{max} &= h_{min}\times(\triangle p)\\ \triangle p &= p_{max}-p_{min} \end{aligned} Vmax△p=hmin×(△p)=pmax−pmin
其中 h m i n h_{min} hmin 是两块板中较小的高度, p m a x p_{max} pmax 是两块板中较大的编号, p m i n p_{min} pmin 是较小的编号换言之,体积 V V V 只受到两个因素(变量)的影响, h m i n h_{min} hmin 和 △ p \triangle p △p
我们只要先将一个变量控制住(将他按从大到小的规律排序),再去贪另一个变量即可达到目的
题解中大多数的双指针法,就是控制 △ p \triangle p △p 从大到小(指针从两段向里走),然后去贪尽可能高的 h m i n h_{min} hmin
这种做法无需更多的排序
-
对h排序的做法
同样的,我们也可以控制h:
-
将h从高到低排序,依次取出最高的板
-
同时我们要想办法让 △ p \triangle p △p 尽可能的大,即如果新取出的板的坐标大于 p m a x p_{max} pmax 或小于 p m i n p_{min} pmin 就更新这两个p值
再换一种说法加深理解:
由于我们在不断的取出更短的板, h m i n h_{min} hmin 就不可避免的在变小
(要注意,能控制体积的高度只有 h m i n h_{min} hmin,且就是当前取出来的这块板的高度)
所以所能控制的就是让 △ p \triangle p △p 更大
-
-
代码
//结构体确保板的高度和下标能一一对应,当然这里还有其他做法,如make_pair<int, int> struct node { int height; int pos; friend bool operator<(node a, node b) { return a.height < b.height; } friend bool operator>(node a, node b) { return a.height > b.height; } }; class Solution { public: int maxArea(vector<int>& height) { priority_queue<node, vector<node>, less<node>> que;//优先队列实现排序 for (int i = 0; i < height.size(); i++) { que.push({height[i], i}); } //取出最高的两块板 node b1 = que.top(); que.pop(); node b2 = que.top(); que.pop(); //获取pmax和pmin int pmax, pmin; if (b1.pos > b2.pos) pmax = b1.pos, pmin = b2.pos; else pmax = b2.pos, pmin = b1.pos; int vmax = (pmax - pmin) * b2.height; //主体部分 while (!que.empty()) { //拿出下一个最高的板子 node tmp = que.top(); que.pop(); //只有在[pmin, pmax]区间外的板子可能有效 if (tmp.pos < pmin) { //计算新板子与之前两块板子所能构成的最大容积 vmax = max(vmax, (pmax - tmp.pos) * tmp.height); //更新pmin/pmax的值,让pmax尽可能大, pmin = tmp.pos; } else if (tmp.pos > pmax) { vmax = max(vmax, (tmp.pos - pmin) * tmp.height); pmax = tmp.pos; } } return vmax; } };
-
因为有一个堆排,相比直接的双指针法效率肯定更低,但从理解贪心的思想上,换一种方式可能会更有帮助