|
|
// 接雨水问题
#include<iostream>
using namespace std; /*
*暴力法:每个柱子顶部可以储水的高度为:该柱子的左右两侧最大高度的较小者减去此柱子的高度。因此我们只需要遍历每个柱子,累加每个柱子可以储水的高度即可。 */ int JieYuShui1(int height[], int len){ int res = 0; // 遍历每个柱子
for (int i = 1; i < len - 1; i++) { int leftMax = 0, rightMax = 0; // 计算当前柱子左侧的柱子中的最大高度
for (int j = 0; j <= i; j++) { leftMax = max(leftMax, height[j]); } // 计算当前柱子右侧的柱子中的最大高度
for (int j = i; j < len; j++) { rightMax = max(rightMax, height[j]); } // 结果中累加当前柱子顶部可以储水的高度,
// 即 当前柱子左右两边最大高度的较小者 - 当前柱子的高度。
res += min(leftMax, rightMax) - height[i]; } return res; }
/*
*动态规划:对于每个柱子,我们都需要从两头重新遍历一遍求出左右两侧的最大高度,这里是有很多重复计算的,很明显最大高度是可以记忆化的,具体在这里可以用数组边递推边存储,也就是常说的动态规划,DP。 1定义二维dp数组 int[][] dp = new int[n][2],其中,dp[i][0] 表示下标i的柱子左边的最大值,dp[i][1] 表示下标i的柱子右边的最大值。2分别从两头遍历height数组,为 dp[i][0]和 dp[i][1] 赋值。3同方法1,遍历每个柱子,累加每个柱子可以储水的高度。 */ int JieYuShui2(int height[], int len){ int res = 0; if (len == 0) { return 0; } // 定义二维dp数组
// dp[i][0] 表示下标i的柱子左边的最大值
// dp[i][1] 表示下标i的柱子右边的最大值
int dp[len][2]; dp[0][0] = height[0]; dp[len - 1][1] = height[len - 1]; for (int i = 1; i < len; i++) { dp[i][0] = max(height[i], dp[i - 1][0]); } for (int i = len - 2; i >= 0; i--) { dp[i][1] = max(height[i], dp[i + 1][1]); } // 遍历每个柱子,累加当前柱子顶部可以储水的高度,
// 即 当前柱子左右两边最大高度的较小者 - 当前柱子的高度。
for (int i = 1; i < len - 1; i++) { res += min(dp[i][0], dp[i][1]) - height[i]; } return res; }
/*
*双指针:在上述的动态规划方法中,我们用二维数组来存储每个柱子左右两侧的最大高度,但我们递推累加每个柱子的储水高度时其实只用到了 dp[i][0]和 dp[i][1] 两个值,因此我们递推的时候只需要用 int leftMax 和 int rightMax 两个变量就行了。 */ int JieYuShui3(int height[], int len){ int res = 0; int leftMax = 0, rightMax = 0, left = 0, right = len - 1; while (left <= right) { if (leftMax <= rightMax) { leftMax = max(leftMax, height[left]); res += leftMax - height[left++]; } else { rightMax = max(rightMax, height[right]); res += rightMax - height[right--]; } } return res; }
int main(){ int arr[] = {0,1,0,2,1,0,1,3,2,1,2,1}; int len = sizeof(arr) / sizeof(arr[0]); int res = JieYuShui3(arr, len); cout<<res<<endl; return 0; }
|