對於數組 A , 怎麼求的Max((j - i) * [min (A[i] , A[j])]) , 其中 i , j < A.length - 1
這道題目, 暴力的話,很容易, O(n^2) , 可是採用頭尾指針的方法可以在O(n)的時間內完成!
O(n) 的代碼 及其簡單,就是頭尾指針,誰小誰移動,然後,求兩個指針間的面積,再更新
最大面積即可。
但是,爲什麼?爲什麼這個方法能行了?
比如 : 數組A[3 , 7 , 4 , 8 , 5]
暴力的話,就是:
3 7 3
3 4 6
3 8 9
3 5 12
7 4 4
.....
8 5 5
觀察上面的可以知道:
以A[0] = 3 爲一條邊的話,那麼高度最大爲3 , 所以,如果底邊能最大 , 就能找到最大面積
所以,就可以採用尾指針從尾部遍歷。
如果它比3小,那麼就要在0 - A.length - 2中找 , 因爲在這裏面可能還存在面積更大的,而這個
面積最大的臨界情況就是第一個>=3! 因爲滿足底最大! 那麼接下來就不要比較A[1],A[2],A[3] 構成的大小,他們 一定比A[0]A[4]小!這樣不就減少了沒用的計算。直接進入A[1] = 7;
同理,以A[1] = 7 爲高 , 查找第一個>=7的 , 但是,可能會想,已經過濾的尾部的元素
不會與7構成一個更大的元素嗎?比如,如果上面數組在5後面有一個2 , 那麼以A[0] = 3爲邊時,就已經
被過濾掉了,不會在於其他元素比較了?爲什麼這能行了?
可以這樣考慮,它既然比3小,那麼他就一定比7小(因爲只有最小的那個元素在移動的啊),對吧!所以,
它與3爲邊時,底邊還長1了,怎麼可能與7再構成一個更大的面積!這又是在去除沒用的計算。
所以,7 就只要關心,看能否與當前尾指針所指的元素及其前面的元素構成一個更大面積!
如此,一路遍歷,直到頭指針 >= 尾指針
總結:
關鍵的地方就在於頭尾指針的使用,我覺得他們的作用就是一種標誌!
標誌,實際可能產生最大面積的範圍
以上只是個人的一些粗陋的理解.......
代碼:
public static int maxArea(int[] height) {
int maxWater=0, left=0, right=height.length-1;
//頭尾指針
while(left<right) {
maxWater = Math.max(maxWater,(right-left)*Math.min(height[left], height[right]));
if(height[left]<height[right]) left++;
else right--;
}
return maxWater;
}