字节跳动2018校招后端方向 [编程题]用户喜好

题目描述:

时间限制:C/C++ 3秒,其他语言6秒

空间限制:C/C++ 256M,其他语言512M

为了不断优化推荐效果,今日头条每天要存储和处理海量数据。假设有这样一种场景:我们对用户按照它们的注册时间先后来标号,对于一类文章,每个用户都有不同的喜好值,我们会想知道某一段时间内注册的用户(标号相连的一批用户)中,有多少用户对这类文章喜好值为k。因为一些特殊的原因,不会出现一个查询的用户区间完全覆盖另一个查询的用户区间(不存在L1<=L2<=R2<=R1)。

思路:

我的思路:

因为询问区间保证了不会出现覆盖,那么如果将询问区间对左端点排序的话,就会出现下图这样

也就是说,如果对左端点排序,右端点一定是不断变大的。因为l1<=l2,所以r2>r1一定成立,否则就会与条件冲突。

所以我们维护双指针,用sum[maxn]标记离散化后的数i在已经扫过的区域内出现的次数的和。

右指针右移,sum[a[i]]++,左指针右移,sum[a[i]]--,这样就像是一个前缀和的性质,扫一遍复杂度O(n),还有离散化操作,应该是O(nlogn)的复杂度。

但是我只过了70%,没有检查出错,可能是数据随机并没有满足题目中的条件,也希望各位大佬帮我查查错。

#include <bits/stdc++.h>
using namespace std;

const int maxn=3e5+10;
vector<int>v;
int getid(int cur){
    return lower_bound(v.begin(),v.end(),cur)-v.begin()+1;
}

struct Node{
    int l,r;
    int k;
    int id;
}node[maxn];
int a[maxn];
int sum[maxn];
int ans[maxn];
int cmp(const Node a,const Node b){
    return a.l<b.l||(a.l==b.l&&a.r<b.r);
}
signed main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        v.push_back(a[i]);
    }
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
    int q;
    scanf("%d",&q);
    for(int i=1;i<=q;i++){
        scanf("%d%d%d",&node[i].l,&node[i].r,&node[i].k);
        node[i].id=i;
    }
    sort(node+1,node+q+1,cmp);
    int l=1,r=1;
    int cur=1;
    while(cur<=q){
        while(r<=node[cur].r){
            sum[getid(a[r])]++;
            r++;
        }
        while(l<node[cur].l){
            sum[getid(a[l])]--;
            l++;
        }
        int now=sum[getid(node[cur].k)];
        ans[node[cur].id]=now;
        cur++;
    }
    for(int i=1;i<=q;i++){
        printf("%d\n",ans[i]);
    }
    return 0;

}

大佬的思路:

简单明了,维护一个值k的出现序列vector,如果有询问l,r,k,直接在vector中二分到l-1和r这个区间,看这个区间的长度有多长,就说明这个区间内有多少个k,不得不说这是我见过最简单明了的思路了。

#include <bits/stdc++.h>
using namespace std;
map<int, vector<int> >ma;
int n, q, t;
int l, r, k;
int solve(int l, int r, int k) {
    if (ma[k].size() == 0) return 0;
    auto it1 = lower_bound(ma[k].begin(), ma[k].end(), l);
    auto it2 = upper_bound(ma[k].begin(), ma[k].end(), r);
    return it2 - it1;
}
int main() {
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        cin >> t;
        ma[t].push_back(i);
    }
 
    cin >> q;
    for (int i = 0; i < q; ++i) {
        cin >> l >> r >> k;
        cout << solve(l, r, k) << endl;
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章