class Solution {
// 动态规划法,求左边最高的墙和右边最高的墙
public int trap(int[] height) {
int sum = 0;
int[] max_left = new int[height.length];
int[] max_right = new int[height.length];
for (int i = 1; i < height.length - 1; i++){
max_left[i] = Math.max(max_left[i-1],height[i-1]);
}
for (int i = height.length - 2; i >= 0; i--){
max_right[i] = Math.max(max_right[i+1],height[i+1]);
}
for(int i = 1; i < height.length - 1; i++){
int min = Math.min(max_left[i],max_right[i]);
if(min > height[i]){
sum += min - height[i];
}
}
return sum;
}
}
备忘录优化:
class Solution {
public int trap(int[] height) {
if(height.length<=0){
return 0;
}
int n = height.length;
int res = 0;
int[] l_max = new int[n];
int[] r_max = new int[n];
l_max[0] = height[0];
r_max[n-1] = height[n-1];
for(int i=1;i<n;i++){
l_max[i] = Math.max(l_max[i-1],height[i]);
}
for(int i=n-2;i>=0;i--){
r_max[i] = Math.max(r_max[i+1],height[i]);
}
for(int i=1;i<n-1;i++){
res+=Math.min(l_max[i],r_max[i])-height[i];
}
return res;
}
}
暴力法每到一个位置的时候都需要来计算左右两边的值,所以我们可以提前把l_max和r_amx计算出来并记录在“备忘录”中,用到的时候直接取就行。
时间复杂度:O(n)
空间复杂度:O(n)
双指针优化:
class Solution {
public int trap(int[] height) {
int n = height.length;
int l_max = 0;//代表左边最高的水柱
int r_max = 0;//代表右边最高的水柱
int left = 0;
int right = n-1;
int res = 0;
while(left<right){
l_max = Math.max(l_max,height[left]);
r_max = Math.max(r_max,height[right]);
if(l_max < r_max){
res+=l_max-height[left];
left++;
}else{
res+=r_max-height[right];
right--;
}
}
return res;
}
}
边计算边取值,很强。
时间复杂度:O(n)
空间复杂度:O(1)
class Solution {
public int trap(int[] height) {
if(height==null || height.length<=1) return 0;
int n=height.length;
int ans=0;//储水面积
int l_max=0;
int r_max=0;
int left=0;
int right=n-1;
while(left<=right){
l_max=Math.max(l_max,height[left]);
r_max=Math.max(r_max,height[right]);
if(l_max<r_max){
ans+=l_max-height[left];
left++;
}else{
ans+=r_max-height[right];
right--;
}
}
return ans;
}
}
共以下 8 个回答
class Solution {
public int trap(int[] height) {
int n = height.length;
if(n 0 || n 1) return 0;
}
class Solution {
public int trap(int[] height) {
int[] water = new int[height.length];
int i = 0;
int ans = 0;
while(i < height.length){
int curentHeight = height[i];
int j = i + 1;
while(j < height.length){
if(height[j] < height[i])
j++;
else
break;
}
if(j < height.length){
for(int k = i + 1; k < j; k++ )
water[k] = height[i];
}
i = j ;
}
i = height.length – 1;
while(i >= 0){
int j = i – 1;
while(j >= 0){
if(height[j] < height[i])
j–;
else
break;
}
if(j >= 0 ){
for(int k = i – 1; k > j; k– )
water[k] = height[i];
}
i = j ;
}
for(int h = 0; h < height.length; h++)
ans += Math.max(water[h] – height[h],0);
return ans;
}
}
//来回两次遍历 时间复杂度On 空间复杂度On
class Solution {
public int trap(int[] height) {
int ans = 0;
int i = 0;
int leftMax = height[i];
int j = height.length – 1;
int rightMax = height[j];
while(i < j){
if(height[i] < height[j]){
ans += leftMax – height[i];
i++;
leftMax = Math.max(leftMax,height[i]);
}
else{
ans += rightMax – height[j];
j–;
rightMax = Math.max(rightMax,height[j]);
}
}
return ans;
}
}//优化法 空间复杂度降到O1
想起来很困难但实现起来很容易的解法,时间复杂度$O(n)$,空间复杂度$O(n)$
时间复杂度:O(n)
空间复杂度:O(n)
在备忘录解法中,l_max[i]和r_max[i]代表的是height[0..i]和height[i..end]的最高柱子高度。
在双指针解法中,l_max和r_max代表的是height[0..left]和height[right..end]的最高柱子高度。
时间复杂度:O(n)
空间复杂度:O(1)
class Solution {& height) { l(n), r(n);
public:
int trap(vector
int n = height.size();
if(n 0) return 0;
vector
int res = 0;
l[0] = height[0], r[n – 1] = height[n – 1];
// res += min(l[i], r[i]) – height[i]
for(int i = 1; i < n; i ++) {
l[i] = max(l[i – 1], height[i]);
}
for(int i = n – 2; i >= 0; i –) {
r[i] = max(r[i + 1], height[i]);
}
for(int i = 0; i < n; i ++) {
res += min(l[i], r[i]) – height[i];
}
return res;
}
};
时空复杂度
O(N)
思路:两次遍历,第一次正序遍历,记录每个位置的左边最大值;第二次逆序遍历,记录每个位置的右边最大值。
“`c++& height) { leftHeight(n, 0);=1; i–) {
class Solution {
public:
int trap(vector
int n = height.size();
vector
int maxiL = height[0];
for (int i=1; i
if (height[i] > maxiR) {
maxiR = height[i];
} else if (height[i] <= leftHeight[i]) { res += min(maxiR, leftHeight[i]) - height[i]; }
};
“`