力扣11 盛最多水的容器 非双指针 主要谈谈对于贪心的理解

  • 前言
    传送门

    看讨论区和题解区清一色都是双指针

    确实这道题双指针时间空间最优

    但还是想分享一下对于贪心的一些理解,和从另一种角度出发的算法

  • 对题目的理解

    很容易可以得到这道题的体积公式:
    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} Vmaxp=hmin×(p)=pmaxpmin
    其中 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;
        }
    };
    
  • 因为有一个堆排,相比直接的双指针法效率肯定更低,但从理解贪心的思想上,换一种方式可能会更有帮助

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cishoon

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值