直方图装水的格数最大问题

问题描述:
给定一个正整数数组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";
} 

}

第三种解法很帅,配个图
pic

纸上得来终觉浅,须知此事要躬行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值