[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倍,不過優點是能求出方案數?雖然說在這題裏並沒有什麼卵用

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章