之前在CSDN看到过这道题,感觉挺有趣的,之后又遇到了,这里分享一下相关问题的解法。(试题分析参考:我的Twitter技术面试失败了)
看下面这个图片”
“在这个图片里我们有不同高度的墙。这个图片由一个整数数组所代表,数组中每个数是墙的高度。上边的图可以表示为数组[2,5,1,2,3,4,7,7,6]”
“假如开始下雨了,那么墙之间的水坑能够装多少水呢?”
“以1×1的方块为单位计算容积。所以,在上边的图中下标为1以左的都会漏掉。下标7以右的也会漏掉。剩下的只有在1和6之间的一坑水,容积是10”
逻辑如下:
如果我们从左至右遍历列表,每个下标水的量最多是到现在为止最大的数。这表示如果我们已知右边有相等或更大的,我们可以知道存下的水有多少。反向遍历的时候也一样:如果我们知道左边有比右边最大的数更大的,我们装水是毫无问题的。
基于这个想法,一个解决方法是:先找到最大值,从左遍历到最大值,然后从右遍历到最大值。这个方法需要两次遍历:一次找到最大值,另一次分成了两个子遍历。
一次遍历的方法通过两端的指针相向移动避免了寻找最大值。如果(左指针找到的左指针以左的最大值)小于(右指针找到右指针以右的最大值),将左指针向右移动一位。否则右指针向左移动一位。重复过程直到两个指针相遇。(解释起来很麻烦,但是代码很简单)
相关代码可以参考:https://github.com/CuGBabyBeaR/Interview-questions/tree/master/twitter-puddle其中C++:
/*
* CuGBabyBeaR
*/
#include "stdio.h"
int volume_calcuate(int[],int);
int main(int argc, char const *argv[]){
int testcase_1[9] = {2,5,1,2,3,4,7,7,6};
int testcase_2[10] = {2,5,1,3,1,2,1,7,7,6};
int testcase_3[9] = {6,1,4,6,7,5,1,6,4};
printf("Case testcase_1 total volume : %i\n",volume_calcuate(testcase_1,9));
printf("Case testcase_2 total volume : %i\n",volume_calcuate(testcase_2,10));
printf("Case testcase_3 total volume : %i\n",volume_calcuate(testcase_3,9));
return 0;
}
int volume_calcuate(int walls[] , int length){
int * p_l = &walls[0];
int * p_r = &walls[length-1];
int max_l = walls[0];
int max_r = walls[length-1];
int total_volume = 0;
while(p_r > p_l){
if (max_l < max_r){
p_l++;
if (*p_l >= max_l){
max_l = *p_l;
}else{
total_volume += max_l - *p_l;
}
}else{
p_r--;
if (*p_r >= max_r){
max_r = *p_r;
}
else{
total_volume += max_r - *p_r;
}
}
}
return total_volume;
}