[LeetCode 11]盛最多水的容器 二分

emmm看到这题第一反应是二分_(:з」∠)_
首先可以观察到,假设我们目前敲定了2块板l和r,那么在l和r之间,低于l和r的板子都是无效的(这个应该显而易见)。
基于这个性质对无效板进行消除,最后会得到一个山峰形(先单调不降,后单调不升)

现在考虑对山峰形如何求解。
考虑枚举每个有效板作为边界,寻求使得答案最大的另一块板。

因为2块板子决定高度的是短板,所以我们用短板来找长版。
对于山峰左侧的板子x,我们找在山峰右侧的距离它最远的比它高的板子。因为山峰右侧是单调不升,所以可以二分。
为什么一定是山峰右侧?因为任意山峰左侧的板子都可以用距离x最远的山峰来替代(山峰一定比左侧的板子更靠右,即更远,也更高,即一定不比x低)

同理,对于山峰右侧的板子x,我们找在山峰左侧距离它最远的比它高的板子。因为山峰左侧单调不降,所以也可以二分解决。

最后对于求出的若干的最大值取max即可。

class Solution {
public:
    vector<int> s;
    vector<int> id;
    int half1(int l, int r, int x){//查找l, r区间距离l最远的比x大的位置,递减区间,相当于找比x大的最小值
        while(l < r){
            int mid = (l + r + 1) >> 1;
            if(s[mid] >= x) l = mid;
            else r = mid - 1;
        }
        return l;
    }

    int half2(int l, int r, int x){//查找l, r区间距离r最远的比x大的位置,递增区间,相当于找比x大的最小值
        while(l < r){
            int mid = (l + r) >> 1;
            if(s[mid] >= x) r = mid;
            else l = mid + 1;
        }
        return l;
    }
    //永远用低侧找高侧
    int maxArea(vector<int>& height) {//先筛选成山峰形
        int maxn = 0;
        for(int i = 1; i < height.size(); i ++)
            if(height[i] > height[maxn]) maxn = i;//找山顶

        for(int i = 0; i <= maxn; i ++)
            if(i == 0 || height[i] > s[s.size() - 1]) s.push_back(height[i]), id.push_back(i);
        int pos = s.size() - 1;//记录山顶位置,第一个山顶
        vector<int> ss;
        vector<int> tmp;
        for(int i = height.size() - 1; i > maxn; i --)
            if(ss.size() == 0 || height[i] > ss[ss.size() - 1]) ss.push_back(height[i]), tmp.push_back(i);
        for(int i = ss.size() - 1; i >= 0; i --) s.push_back(ss[i]), id.push_back(tmp[i]);
        int back_pos = s.size() - 1;
        for(int i = s.size() - 1; i >= 0; i --) 
            if(s[i] > s[back_pos]) back_pos = i;//找最后一个山顶
        int ans = 0;
        for(int i = 0; i < pos; i ++){
            int far = half1(pos, s.size() - 1, s[i]);
            ans = max(ans, (id[far] - id[i]) * s[i]);
        }
        for(int i = pos + 1; i < s.size(); i ++){
            int far = half2(0, back_pos, s[i]);
            ans = max(ans, (id[i] - id[far]) * s[i]);
        }
        return ans;
    }
};

大概是比双指针复杂了n倍,不过优点是能求出方案数?虽然说在这题里并没有什么卵用

posted @ 2023-08-29 02:31  ww3113306  阅读(11)  评论(0编辑  收藏  举报
知识共享许可协议
本作品采用知识共享署名-非商业性使用-禁止演绎 3.0 未本地化版本许可协议进行许可。