计算题
计算题
http://www.nowcoder.com/questionTerminal/769e5e6c3ebf42a49cfb555ebf4a90e2
题解
难度:较难
知识点:分割字符串、数组、数学逻辑
解题思路:这道题主要在数学逻辑上具有较大的难度。解决这种数组问题,一定要想好数据的保存方式,再者这道题在输入中涉及到了字符串的分割,只有将字符串分割出来保存进数组才能使用这些数字。整道题将涉及到比较难的数学思维,以下将逐一介绍方法。
方法一:暴力解算(不能运行,运行超时,但是一种解决思维)
因为需要计算所有的盛水量,所以加入可以计算出每一个位置的盛水量,进行累加即可得到最终结果。但是怎么计算每一个位置的盛水量呢?这里只要确定每个位置,这需要寻找每一位置的左边界left和右边界right,然后比较[left, right]之间取较小值即可。
#include<iostream>
#include <algorithm>
#include<vector>
using namespace std;
int main()
{
vector<int> Heights;
char c;
int flag = 0;
while((c = getchar()) != '\n'){
if(c != ','){
flag = flag * 10 + (c - '0');
} else {
Heights.push_back(flag );
flag = 0;
}
}
Heights.push_back(flag);
long Sum = 0;
int len=Heights.size();
for(int i=1;i<len-1;i++)
{
int LeftMax=0;
int RightMax=0;
for(int j = i - 1; j >= 0; j--)
LeftMax= max(LeftMax,Heights[j]);
for(int k=i+1;k<len;k++)
RightMax= max(RightMax,Heights[k]);
int minval = min(LeftMax, RightMax);
if(minval > Heights[i])
Sum += minval - Heights[i];
}
cout<<Sum<<endl;
return 0;
}方法二(暴力法的优化)
前面因为在每个位置都需要进行两个for循环,在整个运行过程中导致超时,所以可以进行优化,直接采用两个数组保存每个位置最大左、右边界值即可。
#include<iostream>
#include <algorithm>
#include<vector>
using namespace std;
int main()
{
vector<int> Heights;
char c;
int flag = 0;
while((c = getchar()) != '\n'){
if(c != ','){
flag = flag * 10 + (c - '0');
} else {
Heights.push_back(flag );
flag = 0;
}
}
Heights.push_back(flag );
long Sum = 0;
int len=Heights.size();
int left_max[len];
int right_max[len];
left_max[0] = Heights[0];
right_max[len - 1] = Heights[len - 1];
for (int i = 1; i < len; i++) {
left_max[i] = max(Heights[i], left_max[i - 1]);
right_max[len - i - 1] = max(Heights[len-i-1], right_max[len-i]);
}
for (int i = 1; i < len - 1; i++) {
Sum += min(left_max[i], right_max[i]) - Heights[i];
}
cout<<Sum<<endl;
return 0;
}方法三(双指针逼近)
使用两个指针标记,夹近这个值。
(1)设置两个索引值:
左边界索引left和右边界索引right
左边界索引:从数组头到数组尾方向,第一次出现下降趋势的位置。
右边界索引:从数组尾到数组头方看,第一次出现下降趋势的那个索引的位置。
(2)记录左边界和右边界的高度,记作leftHeight和rightHeight。如果left < right,说明左右边界还没有重合,令left加1。如果left位置能够存储雨水,则更新结果的值。如果此位置不能存储雨水,需要进入下一轮循环,更新leftHeight的值。如果left < right,说明左右边界还没有重合,令right减1。如果right位置能够存储雨水,则更新结果的值。如果right位置不能存储雨水,进入下一轮循环,更新rightHeight的值。
#include<iostream>
#include <algorithm>
#include<vector>
using namespace std;
int main()
{
//分割这个字符串,将数字保存进vector里
vector<int> Heights;
char c;
int flag = 0;
while((c = getchar()) != '\n'){
if(c != ','){
flag = flag * 10 + (c - '0');
}
else {
Heights.push_back(flag);
flag = 0;
}
}
Heights.push_back(flag);
long Sum = 0;
int len=Heights.size();
int left = 0;
while(left < len - 1 && Heights[left + 1] >= Heights[left]) {
left++;
}
int right = len - 1;
while(right >= 1 && Heights[right - 1] >= Heights[right]) {
right--;
}
while(left < right) {
int leftHeight = Heights[left];
int rightHeight = Heights[right];
if(leftHeight <= rightHeight) {
while(left < right) {
left++;
if(Heights[left] < leftHeight) {
Sum += leftHeight - Heights[left];
}
else
break;
}
}
else {
while(left < right) {
right--;
if(Heights[right] < rightHeight) {
Sum += rightHeight - Heights[right];
}
else
break;
}
}
}
cout<<Sum<<endl;
return 0;
}
联想公司福利 1493人发布