Mountains(CVTE面试题)解题报告

题目大意:

用一个数组代表群山的高度。高度大的地方代表山峰,小的地方代表山谷。山谷可以容水。假设有一天下了大雨,求群山中总共可以容纳多少水?

如图所示情况,a代表该数组,总共可以容纳5个水。

解题思路:

初步想法可以枚举每一个单位,判断是否能放水。这种做法的复杂度为O(n^2*h)其中h为数组最大值,n为数组的大小。效率较低。

进一步观察发现:由于只有山谷可以存水,假设a[i],a[j]>a[k](i<k<j),那么i,j之间的水量可以直接算出,问题降解为两个子问题:求0到i的存水量和j到n-1的存水量

代码:

#include <iostream>
#include <algorithm>
#define maxn 1000
using namespace std;

int hills[maxn];
int highest[maxn][maxn];
int highone[maxn][maxn];
int stones[maxn][maxn];
int total = 0;
int n;

int calWater(int f, int t) {
    //not yet implemented
    if (f+1==t)
        return 0;
    return (t-f-1)*min(hills[f], hills[t])-stones[f+1][t-1];
}

void solve(int f, int t) {
    if (f >= t)
        return;
    int n1, n2;
    n1 = highone[f][t];
    n2 = highest[f][n1-1] > highest[n1+1][n-1] ? highone[f][n1-1] : highone[n1+1][n-1];
if (n1 > n2) {
        swap(n1, n2);
    }
    total += calWater(n1, n2);
    solve(f, n1);
    solve(n2, t);
}

int main() {
    int i;
    cin >> n;
    for (i = 0; i < n; i++) {
        cin >> hills[i];
    }
    for (i = 0; i < n; i++) {
        highest[i][i] = hills[i];
        stones[i][i] = hills[i];
        highone[i][i] = i;
    }
    int step = 2;
    int f,t,m;
    while (step <= n) {
        for (i = 0; i <= n-step; i++) {
            f = i;
            t = i+step-1;
            m = (f+t)/2;
            highest[i][i+step-1] = max(highest[i][m], highest[m+1][i+step-1]);
            highone[i][i+step-1] = highest[i][m] > highest[m+1][i+step-1] ? highone[i][m] : highone[m+1][i+step-1];
            stones[i][i+step-1] = stones[i][m] + stones[m+1][i+step-1];
        }
        step++;
    }
    solve(0, n-1);
    cout << total << endl;
}

心得体会:

下面一行为吐槽请绕过。

{面试的时候被面试官问傻了(哭,连最简单的方法都没讲出来。唉,估计是终身遗憾了。不过下次面试应该会更轻松一些。要抓紧复习基础知识才行啊!}

这道题虽然简单但是用了分治的思想。没有想到更好的解法,希望有大神指点迷津!

 

更好的解法!(感谢@MchCyLh)

解题思路:见一楼评论

代码:

#include <iostream>
#include <algorithm>

#define maxn 1000

using namespace std;

int a[1000];

int main() {
    int n, i;
    cin >> n;
    for (i = 0; i < n; i++) {
        cin >> a[i];
    }
    int l, hl, r, hr, tot = 0;
    l = hl = 0;
    r = hr = n-1;
    while (r-l>1) {
        if (a[hl] < a[hr]) {
            i = ++l;
            while (i < r && a[i] <= a[hl]) {
                tot += a[hl]-a[i];
                l++;
                i++;
            }
            if (i != n) {
                hl = i;
            }
        } else {
            i = --r;
            while (i > l && a[i] <= a[hr]) {
                tot += a[hr]-a[i];
                r--;
                i--;
            }
            if (i != -1) {
                hr = i;
            }
        }
        
    }
    cout << tot << endl;
}

复杂度降为O(n)www

 

posted @ 2016-03-17 00:37  IVY_BUG  阅读(216)  评论(3编辑  收藏  举报