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