问题描述:
给定一个正整数数组arr,把arr想象成一个直方图。 返回这个直方图如果装水,最多能装下几格水?
/** 题目描述:给定一个正整数数组arr,把arr想象成一个直方图。
* 返回这个直方图如果装水,能装下几格水?
*/
#include <iostream>
#include <algorithm>
namespace cc_01_histogramWater
{
/** 直方图装水解法1:每次遍历到一个位置,求出左边最大与右边最大。
* @param arr:数组名
* @param n :数组大小
* @return 最多装下水的格数
*/
int solution1(int* arr, int n) {
if (n <= 2)
return 0;
int water = 0;
int lmax = 0, rmax = 0;
for (int i = 1; i < n - 1; ++i) {
// 求 Lmax
for (int j = i - 1; j >= 0; --j) {
lmax = std::max(lmax, arr[j]);
}
// 求 Rmax
for (int j = i + 1; j < n; ++j) {
rmax = std::max(rmax, arr[j]);
}
water += lmax < rmax ? \
(lmax <= arr[i] ? 0 : lmax - arr[i]) : \
(rmax <= arr[i] ? 0 : rmax - arr[i]);
}
return water;
}
/** 直方图装水解法2:对数组预处理,得到对于每个位置i,
* 其左边最大值和右边最大值数组存储 。
* @param arr:数组名
* @param n :数组大小
* @return 最多装下水的格数
*/
int solution2(int* arr, int n) {
if (n <= 2)
return 0;
int* Lmax = new int[n]; // 记得delete
int* Rmax = new int[n];
Lmax[0] = arr[0];
Rmax[n - 1] = arr[n - 1];
// Lmax[i]: [0, i]的最大值
for (int i = 1; i < n; ++i) {
Lmax[i] = std::max(Lmax[i - 1], arr[i]);
}
// Rmax[j]: [j, n - 1]的最大值
for (int j = n - 2; j >= 0; --j) {
Rmax[j] = std::max(Rmax[j + 1], arr[j]);
}
int water = 0;
for (int k = 1; k < n - 1; ++k) { // 遍历原数组,记录water值
water += Lmax[k - 1] < Rmax[k + 1] ? \
(Lmax[k - 1] <= arr[k] ? 0 : Lmax[k - 1] - arr[k]) : \
(Rmax[k + 1] <= arr[k] ? 0 : Rmax[k + 1] - arr[k]);
}
delete[] Rmax;
delete[] Lmax;
return water;
}
/** 直方图装水解法3:每次遍历到一个位置,双指针法夹逼,就地操作,具体操作见图。
* @param arr:数组名
* @param n :数组大小
* @return 最多装下水的格数
*/
int solution3(int* arr, int n) {
if (n <= 2)
return 0;
int left = 1, right = n - 2;
int water = 0;
int leftMax = arr[0], rightMax = arr[n - 1];
while (left <= right) {
if (leftMax <= rightMax) {
water += arr[left] < leftMax ? (leftMax - arr[left]) : 0;
leftMax = std::max(leftMax, arr[left++]);
}
else {
water += arr[right] < rightMax ? rightMax - arr[right] : 0;
rightMax = std::max(rightMax, arr[right--]);
}
}
return water;
}
// for test
void test() {
std::cout << "cc_01_histogramWater test {\n";
int arr[] = {9, 2, 1, 4, 7, 5, 6, 8, 3};
std::cout << "直方图装水解法1(最大格数):" << std::endl;
std::cout << solution1(arr, sizeof(arr) / sizeof(arr[0])) << "\n\n";
std::cout << "直方图装水解法2(最大格数):" << std::endl;
std::cout << solution2(arr, sizeof(arr) / sizeof(arr[0])) << "\n\n";
std::cout << "直方图装水解法3(最大格数):" << std::endl;
std::cout << solution3(arr, sizeof(arr) / sizeof(arr[0])) << "\n\n";
std::cout << "}\n\n";
}
}
第三种解法很帅,配个图
纸上得来终觉浅,须知此事要躬行。