1.对于这道题自然想到暴力求解:
就是记录下两两之间的容量结果,并记录下最大值
class Solution {
public:
int maxArea(vector<int>& height) {
int max_x = 0,max_y = 0,res = 0;
for(int i = 0;i<height.size();i++){
for(int j = 1;j<height.size();j++){
max_x = j - i;
max_y = min(height[j],height[i]);
if(res < max_x * max_y) res = max_x*max_y;
}
}
return res;
}
};
但是时间复杂度达到了 O ( n 2 ) O(n^2) O(n2)
2.利用双指针法:
设两指针i
,j
,指向的水槽高度为h[i]
,h[j]
,设水槽面积为S(i,j)
。可容纳水的高度由两个板子之中的短板决定。于是可得面积公式:
S
(
i
,
j
)
=
(
j
−
i
)
∗
m
i
n
(
h
[
i
]
,
h
[
j
]
)
S(i,j)=(j-i)*min(h[i],h[j])
S(i,j)=(j−i)∗min(h[i],h[j])
在每个状态下,无论长板或短板向中间收窄一格,都会导致水槽底边宽度
−1
。
- 如果移动的是短板,
min(h[i],h[j])
可能增大或不变,则S(i,j)
可能增大 - 若向内移动长板 ,水槽的短板
min(h[i],h[j])
不变或变小,因此下个水槽的面积一定变小
。
因此,初始化双指针分列水槽左右两端,循环每轮将短板向内移动一格,并更新面积最大值,直到两指针相遇时跳出;即可获得最大面积。
至此可能有同学会有疑问,在暴力解下会有C(n,2)
种情况。这种解决方法只考虑了n种情况,其余情况如何能直接排除呢?
假设状态 S(i,j)
下 h[i] < h[j]
,在向内移动短板至 S(i+1,j)
,则相当于消去了 S(i,j−1)
,S(i,j−2)
,…,S(i,i+1)
状态集合。而所有消去状态的面积一定都小于当前面积(即 <S(i,j)
),因为这些状态:
短板高度:相比 S(i,j)
相同或更短(即 ≤h[i]
);
底边宽度:相比 S(i,j)
更短;
因此,每轮向内移动短板,所有消去的状态都 不会导致面积最大值丢失 。
注意:消的是S(i,[i+1,j-1])
固定i,
j
∈
[
i
+
1
,
j
−
1
]
j\in[i+1,j-1]
j∈[i+1,j−1]
此时时间复杂度来到:
O
(
n
)
O(n)
O(n)
代码如下:
class Solution {
public:
int maxArea(vector<int>& height) {
int i = 0, j = height.size() - 1, res = 0;
while(i < j) {
res = height[i] < height[j] ? //判断短板
max(res, (j - i) * height[i++]): //移动并更新
max(res, (j - i) * height[j--]);
}
return res;
}
};