链家网-后台开发工程师笔试题-第三题

序言(废话)

今天做链家网的笔试题, 选择题考的好杂好杂啊, php, java, C++ 几乎是等比重的考察,完全没有侧重,完全没有侧重。 幸亏都是基本语法, 大部分只要用心猜(反正编程语言都差不多了,毕竟咱是学C++的, 什么邪恶的写法没见过~~~~)。

然后是笔试题, 其实笔试题三道都挺简单的, 只不过第三道题会卡时间。

题目描述

小恪要给学校里的人分组, 每个人的编号是连续的正整数(从1开始)。 然后根据某些同学的编号,查询它在哪个组里。

输入描述

第一行输入正整数 n, 代表总共有几数, 然后下一行输入 n 个正整数,表示每一个组有几个成员。
第三行输入正整数m, 代表有 m 次的询问。 然后下一行有 m 个正整数, 表示询问编号为 Mi的成员,在哪一组?

5
2 7 3 4 9
3
1 25 11

题目输出

1
5
3

数据范围

1<= N <= 10^5, 1<= 每个组的成员数量 <= 10^6, 1<= M <= 10^5.

解题代码

方法一: 直接做

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <vector>
#include <string>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <unordered_set>
#include <unordered_map>
#include <algorithm>
#include <stdexcept>
using namespace std;

const int maxn = 100000 + 5; 
long long arr[maxn]; 
long long brr[maxn]; 

int main()
{
    int n; 
    cin >> n; 
    arr[0] = 0; 
    for(int i = 1; i <= n; i++)
        cin >> arr[i]; 
    for(int i = 2; i <= n; i++)
        arr[i] = arr[i] + arr[i-1]; 
    
    int m; 
    cin >> m; 
    for(int i = 1; i <= m; i++)
        cin >> brr[i]; 
    for(int i = 1; i <= m; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            if(arr[j] >= brr[i])
            {
                cout << j << endl; 
                break; 
            }
        }
    }       
    
    return 0; 
}

在规定的时间内,通过了 82%样例。 也就是说稍微有些超时~~~

方法二: 用二分查找代替顺序查找

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <vector>
#include <string>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;

const int maxn = 100000 + 5; 
long long arr[maxn]; 
long long brr[maxn]; 

int bSearch(long long arr[], int left, int right, long long val)
{
    while(left < right)
    {
        int mid = left + (right - left)/2;
        if(arr[mid] < val)
            left = mid+1; 
        else if(arr[mid] > val)
            right = mid; 
        else
            return mid; 
    } 
    
    return left; 
}

int main()
{
    int n; 
    cin >> n; 
    arr[0] = 0; 
    for(int i = 1; i <= n; i++)
        cin >> arr[i]; 
    for(int i = 2; i <= n; i++)
        arr[i] = arr[i] + arr[i-1]; 
    
    int m; 
    cin >> m; 
    for(int i = 1; i <= m; i++)
        cin >> brr[i]; 
    for(int i = 1; i <= m; i++)
    {
        cout << bSearch(arr, 1, n+1, brr[i]) << endl; 
    }       
    
    return 0; 
}

然而结果仍然是 82%, 好坑啊, 数据好没区分度啊!!!, 本来以为这种程度的优化绝壁就能过了, 于是就没打算写下面的第三种方法,结果。。。。悲剧了!!!!

方法三: 空间换时间, 排序+hash

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <vector>
#include <string>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <unordered_set>
#include <unordered_map>
#include <algorithm>
using namespace std;

const int maxn = 100000 + 5; 
long long arr[maxn]; 
long long brr[maxn]; 
long long crr[maxn]; 

int main()
{
    int n; 
    cin >> n; 
    arr[0] = 0; 
    for(int i = 1; i <= n; i++)
        cin >> arr[i]; 
    for(int i = 2; i <= n; i++)
        arr[i] = arr[i] + arr[i-1]; 
    
    int m; 
    cin >> m; 
    for(int i = 1; i <= m; i++)
    {
        cin >> brr[i]; 
        crr[i] = brr[i]; 
    }
        
    unordered_map<long long, long long> mm; 
    sort(crr+1, crr+m+1);
    int pos = 1;  
    int i = 1; 
    while(i <= n)
    {
        if(pos > m)
            break; 
            
        while(arr[i] < crr[pos])
            i++; 
        mm[crr[pos]] = i; 
        pos++;  
    }       
    
    for(int i = 1; i <= m; i++)
        cout << mm[brr[i]] << endl; 
        
    return 0; 
}

毫无疑问, 这个提交绝不会超时,因为时间复杂度是O(NlogN)啊, 并且没有常数因子, 线段树也只能是这样的复杂度了吖。 但是, 但是, 链家网用的笔试OJ好差啊, 提交一个题目要十分钟 ~ ~ 。


听说由于这个原因, 最后延时半小时 ~ ~ ~, 可是我已经提前交卷了, ~ ~ ~, 感觉好坑啊。 (当然主要还是怪自己没有再等等 ~ ~ ~)。 写篇博客,总结一下教训,不喜勿喷~~。



posted @ 2017-08-19 21:46  草滩小恪  阅读(...)  评论(... 编辑 收藏