序言(废话)
今天做链家网的笔试题, 选择题考的好杂好杂啊, 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好差啊, 提交一个题目要十分钟 ~ ~ 。
听说由于这个原因, 最后延时半小时 ~ ~ ~, 可是我已经提前交卷了, ~ ~ ~, 感觉好坑啊。 (当然主要还是怪自己没有再等等 ~ ~ ~)。 写篇博客,总结一下教训,不喜勿喷~~。