2018今日头条笔试(第二题)

题目描述

给定一个数组序列,需要选出一个区间,使得该区间是所有区间中经过如下计算的值最大的一个。

区间中的最小数 * 区间所有数的和

最后程序输出经过计算后的最大值即可,不需要输出具体的区间。如给定序列[6,2,1]可得到左右可以选定各个区间的计算值:

[6]=6*6=36

[2]=2*2=4;

[1]=1*1=1;

[6,2]=2*8=16;

[2,1]=1*3=3;

[6,2,1]=1*9=9

则程序输出36

区间所有数字都在【0,100】的范围内。

 

解题思路:

可以看出我们需要维护一个区间,同时我们能知道区间的最小值,和这个区间所有数字的和。

但是,有一点我们可以清楚知道,如果一个区间的最小值已经确定,那么我们就要尽量使得区间的和最大。其实本问题就可以转换到遍历数组,以当前位置为最小值,向左向右>=当前值能扩展的最大距离问题,我们知道这样的方法时间复杂度是O(n^2)。

 

嗯 区间的最小值和区间边界我们可以用单调栈去维护,这样时间复杂度就降到O(n)

 

其实大小都有了,输出区间边界也就不难了。我这里 输出了最大值和 区间的开始结束位置。如果有多个区间=max,我输出的是字典序较小的区间,代码如下:

给几个比较有用的数据

1

0

ans: 

0

1 1

---------------------

9

1 1 1 1 1 1 1 2 2

ans:

11

1 9

----------------

4

1 3 2 4

ans:

18

2 4

----------------

#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
typedef long long ll;
ll a[100010];
class node {
    public:
        ll left, right,x;
};
ll sum[100010];
int main() {
    // 维护一个递增的栈
    int n;
    vector<node> st;
    while (cin>>n) {
        ll ans = -1;
        if (n == 0) {
            cout << 0 << endl << 0 << " " << 0 << endl;continue;
        }
        ll l = 0,  r = 0;
        while (!st.empty()) st.pop_back();
        sum[0] = 0;
        for (int i = 1; i <= n; ++i) {
            scanf("%lld",&a[i]);
            sum[i] = sum[i-1] + a[i];
        }
        for (int i = 1; i <= n; ++i) {
            if (st.empty()) {
                st.push_back({i,i,a[i]});
            } else {
                node u = st.back();
                if (a[i] > u.x) {
                    st.push_back({i,i,a[i]});
                } else {
                    int ileft=0,iright=0;
                    while (!st.empty()) {
                        node v = st.back();
                        if (v.x >= a[i]) {
                            st.pop_back();
                            ileft = v.left;
                            if(st.size()) st.back().right = v.right;
                            ll tmp = (sum[v.right] - sum[v.left-1])*v.x;
                            if (tmp >= ans) {
                                ans = tmp;
                                l = v.left;
                                r = v.right;
                            }
                        } else break;
                    }
                    st.push_back({ileft,i,a[i]});
                }
            }
        }
        while (!st.empty()) {
            node v = st.back();
            st.pop_back();
            if(st.size()) st.back().right = v.right;
            ll tmp = (sum[v.right] - sum[v.left-1])*v.x;
            if (tmp >= ans){
                ans = tmp;
                l = v.left;
                r = v.right;
            }
        }
        cout << ans << endl << l << " " << r << endl;
    }
    return 0;
}

 

posted on 2017-08-23 12:04  Beserious  阅读(937)  评论(0编辑  收藏  举报