2018.8.12 今日头条研发岗笔试题总结

第一题:球场团队数与最大团队的人数
要求:前后左右以及斜对角相邻的算一个团队;
思路:bfs,参考leetcode 200. Number of Islands。要注意的是输入,用逗号隔开,解决方法是每次读取一个数后,都调用cin.get()来清除逗号
代码:

void bfs(vector<vector<int>>& grid, int i, int j, int& num)

{

if(i<0||i>grid.size()-1||j<0||j>grid[0].size()-1||grid[i][j]==0)

return ;

grid[i][j]=0;

++num;

bfs(grid, i-1,j, num);

bfs(grid, i+1,j, num);

bfs(grid, i,j-1, num);

bfs(grid, i,j+1, num);

bfs(grid, i-1,j-1, num);

bfs(grid, i-1,j+1, num);

bfs(grid, i+1,j-1, num);

bfs(grid, i+1,j+1, num);

return ;

}


int main()

{

int M,N;

cin>>M;

cin.get();

cin>>N;

vector<vector<int> > grid(M,vector<int>(N,0));

for(int i=0; i<M; ++i)

{

for(int j=0;j<N;++j)

{

cin>>grid[i][j];

cin.get();

}

}

int num=0, maxNum=0;

for(int i=0; i!=M; ++i)

{

for(int j=0;j!=N; ++j)

if(grid[i][j]==1)

{

int tmpMax=0;

bfs(grid, i, j, tmpMax);

++num;

if(tmpMax>maxNum)

maxNum=tmpMax;

}

}

cout<<num<<","<<maxNum<<endl;

return 0;

}

第二题:区间合并
要求:有多人给出区间,每个人给出多个,要求合并
思路:先排序,排序规则是先左端点升序,相同时右端点升序。leetcode好像有做过类似的。。
ps:这道题的分号逗号有点恶心,要单独处理下。
代码:

#include <string>

#include <vector>

#include <algorithm>

#include <iostream>


using namespace std;


struct Interval {

long long start;

long long end;

Interval() : start(0), end(0) {}

Interval(long long s, long long e) : start(s), end(e) {}

};


bool com(const Interval& a, const Interval& b)

{

if (a.start != b.start)

return a.start < b.start;

if (a.end != b.end)

return a.end < b.end;

return false;

}


void SplitString(const string& s, vector<string>& v, const string& c)

{

string::size_type pos1, pos2;

pos2 = s.find(c);

pos1 = 0;

while (string::npos != pos2)

{

v.push_back(s.substr(pos1, pos2 - pos1));


pos1 = pos2 + c.size();

pos2 = s.find(c, pos1);

}

if (pos1 != s.length())

v.push_back(s.substr(pos1));

}


int main()

{

int m;

cin >> m;


vector<Interval> intervals;

for (int i = 0; i < m; ++i)

{

string s;

cin >> s;

vector<string> v;

SplitString(s, v, ";");

int num = v.size();


for (int j = 0; j < num; ++j)

{

vector<string> v0;

SplitString(v[j], v0, ",");

Interval x;

x.start = stoi(v0[0]);

x.end = stoi(v0[1]);

intervals.push_back(x);

}

}


sort(intervals.begin(), intervals.end(), com);

long long len = intervals.size();

vector<Interval> res;

long long start(0);

long long end(0);


for (long long i = 0; i < len;)

{

start = intervals[i].start;

end = intervals[i].end;

long long j = i + 1;

for (; j < len; ++j)

{

if (end < intervals[j].start)

break;

end = max(end, intervals[j].end);

}

res.push_back(Interval(start, end));

i = j;

}


long long len2 = res.size();

for (long long i = 0; i < len2; ++i)

{

cout << res[i].start << ',' << res[i].end;

if (i != len2 - 1)

cout << ';';

}

}


第三题:满足条件二元数组的最大值
要求:给出一个二元数组(a,b),从中找出两个集合,这两个集合的sum(a)相等,元素不能重复选,求Max sum(b) ,即两个集合的b加起来最大。
想了几分钟没思路,先跳过,后来完全没时间想。

第四题:满足条件的区间数
要求:给定两个长度相同的数组a b,对应区间内,a的最大值小于b的最小值。
思路:开始用暴力dp,dp1[i][j]表示a的i~j区间的最大值,dp2[i][j]表示b的i~j区间的最小值,然后逐次比较,结果空间复杂度过高,过了20%.
优化1:对于双重循环,i这个变量在dp中没有起到作用,因此改成一维数组,过了30%.
优化2:  dp1[j]=max(dp[j-1], a[j]),可以看到, dp1[j]用了一次之后就不需要再用了,因此可以继续优化到O(1), 即dp1 = max(dp1, a[i]),过了70%
代码:【通过率70%】

#include <iostream>

#include <vector>

using namespace std;

int get_min(int a, int b)

{

return a>b?b:a;

}

int get_max(int a, int b)

{

return a>b?a:b;

}

int main()

{

int n; cin>>n;

vector<int> a(n,0);

vector<int> b(n,0);

for(int i=0;i<n;++i)

cin>>a[i];

for(int i=0;i<n;++i)

cin>>b[i];

int dp1;

int dp2;

int res=0;

for(int i=0; i<n; ++i)

{

int j=i;

for(; j<n;++j)

{

if(i==j)

{

dp1=a[i];

dp2=b[i];

}

else

{

dp1 = get_max(dp1, a[j]);

dp2 = get_min(dp2, b[j]);

}

if(dp1<dp2)

++res;

else break;

}

}

cout<<res<<endl;
return 0;

}

第五题:最多能看多少个直播节目
要求:与算法导论的贪心例题类似,不过可以从任意点开始看,一天为M个小时,只能再一个M的周期内看。
思路:这道题主要是描述不清,刚开始直接用算法导论的思路来做,先排序再贪心,AC0%, 后来猜到了题意(真的是完全靠猜,这题的描述不是很准确),稍加修改直接AC。
代码:

#include <iostream>

#include <vector>

#include <utility>

#include <algorithm>

using namespace std;

bool cmp(pair<int, int>& p1, pair<int, int>& p2)

{

return (p1.second<p2.second )||(p1.second==p2.second && p1.first>p2.first);

}

int main()

{

int N, M;

cin>>N>>M;

vector<pair<int, int> > time(N);

for(int i=0; i<N; ++i)

{

int s, t; cin>>s>>t;

if(s>=t)t+=M;

time[i] = make_pair(s,t);

}

sort(time.begin(), time.end(), cmp);

int finalRes=0;

for(int j=0; j<N;++j) //j代表从第j个开始看

{

int res =0;

int cur0 = time[j].first;

int cur =cur0;

for(int i=0; i<N; ++i)

{

if(i+j<N&& time[i].first >= cur)

{

cur = time[i].second;

if(cur<cur0+M)

++res;

else break;

}

if(i+j>=N && time[i].first+M >= cur)

{

cur = time[i].second+M;

if(cur<cur0+M)

++res;

else break;

}

}

if(res>finalRes)

finalRes = res;

}

cout<<finalRes<<endl;

return 0;

}

总结:感觉除了第三道,难度都能接受,比较常规,都可以在平时做的题中找到原型。



#字节跳动##笔试题目#
全部评论
将楼主的代码稍微排了下版, 然后跑了几个测试样例都过了, 不清楚实际能不能 ac #include <iostream> #include <vector> using namespace std; int main() { int N, M; cin >> N >> M; vector<pair<int, int>> time(N); int s, t; for (int i = 0; i < N; i++) { cin >> s >> t; if (s >= t) t += M; time[i] = make_pair(s, t); } sort(time.begin(), time.end(), [](pair<int, int>& p1, pair<int, int>& p2) { return (p1.second == p2.second) ? p1.first > p2.first : p1.second < p2.second; }); int bound = time[0].second; int max_watch = 0; for(int i = 0; i < N; i++) { // 我们需要找的不同的起点, 绝对是在第一个遍历的 end 之前, // 如果在起点在第一个遍历的 end 之后, 岂不是丢掉了 time 中第一个元素, 肯定不是最大值 if (time[i].first >= bound) { break; } int start_time = time[i].first; int cur_time = time[i].second; int watch = 1; for (int j = i+1; j < N; j++) { if (time[j].first < cur_time) { continue; } cur_time = time[j].second; if (cur_time > start_time + M) { break; } else watch++; } max_watch = max(max_watch, watch); } cout << max_watch << endl; return 0; }
点赞
送花
回复
分享
发布于 2018-08-12 19:21
第三天可以建立一个map,key是甲的a减乙的a,value是两个人的b的总和,然后动态规划,最后取key是0的点。最后过了90%,还有10%超时了
点赞
送花
回复
分享
发布于 2018-08-12 14:02
滴滴
校招火热招聘中
官网直投
第三题dp[i][j]表示前i张卡牌里面,当个人积分之差为j时的最大团队积分。dp目标为dp[n][0]。状态转移方程就不贴了,这是一个差分dp。 第四题枚举左端点,max[l,r]是递增的,min[l,r]是递减的。用sparse table预处理以后,可以用二分在lgn时间内找出右端点。
点赞
送花
回复
分享
发布于 2018-08-13 14:47
%%%%%%%
点赞
送花
回复
分享
发布于 2018-08-12 13:38
第四题最后30%是超时了?
点赞
送花
回复
分享
发布于 2018-08-12 13:40
第五题O(n^2)也能过嘛...我当时也是基于算法导论贪心写的,只是对于start > end的情况把end加了M,这样只能对33% 后来想到单纯加M会和开头的重叠,于是第一时间想到是像你一样遍历开始看的节目,但是觉得O(n^2)会超时,就没改了...最后没有时间了
点赞
送花
回复
分享
发布于 2018-08-12 13:51
return (p1.second<p2.second )||(p1.second==p2.second && p1.first>p2.first); 有个小疑问,这里的按second排序后,一定要按first逆序排吗,按first逆序顺序似乎结果是一致的?毕竟cur只会被更新为xx.second?
点赞
送花
回复
分享
发布于 2018-08-12 15:13
另外电视节目那题,可以给一两个样例吗?我自己想测一下我想的方法:化环为直线,就是在time数组末尾再接一个一样的数组,然后遍历N个开始节目。
点赞
送花
回复
分享
发布于 2018-08-12 15:21
第三题直接暴力DFS不知道能不能过? #include<iostream> #include<vector> using namespace std; void dfs(int &maxScore, int aScore, int bScore, int curScore, vector<pair<int, int>> &score, int layer) {     if (aScore>0 && bScore>0 && aScore == bScore)     {         maxScore = curScore < maxScore? maxScore : curScore;         return;     }     if (layer >= score.size())         return;     dfs(maxScore, aScore + score[layer].first, bScore, curScore + score[layer].second, score, layer + 1);     dfs(maxScore, aScore, bScore + score[layer].first, curScore + score[layer].second, score, layer + 1);     dfs(maxScore, aScore, bScore, curScore, score, layer + 1); } int main() {     int n;     cin >> n;     int x, y;     vector<pair<int, int>> score;     for (int i = 0; i < n; i++)     {         cin >> x >> y;         score.push_back({ x, y });     }     int res;     dfs(res, 0, 0, 0, score, 0);     cout << res << endl;     system("pause");     return 0; }
点赞
送花
回复
分享
发布于 2018-08-12 16:51
第五题这个代码只过了22.22%,很迷,给的三个用例都过了啊,请大佬指教 #include<iostream> #include<vector> using namespace std; //最少删除的区间的个数,使得区间没有重叠 int eraseOverlapIntervals(vector<pair<int,int>>& intervals)  {     int res = 0, n = intervals.size(), last = 0;     for (int i = 1; i < n; ++i)      {         if (intervals[i].first < intervals[last].second)          {             ++res;             if (intervals[i].second< intervals[last].second)                  last = i;         }         else          {             last = i;         }     }     return res; } int main() {     int N;     cin >> N;     int M;     cin >> M;     vector<pair<int, int>> intervals;     int start, end;     for (int i = 0; i < N; i++)     {         cin >> start >> end;         if (start > end)             end += M;         intervals.push_back({ start, end });     }     int minErase = eraseOverlapIntervals(intervals);     cout << intervals.si***Erase << endl;     system("pause");     return 0; }
点赞
送花
回复
分享
发布于 2018-08-12 16:52
if(s>=t)t+=M;这一句是什么意思
点赞
送花
回复
分享
发布于 2018-08-12 18:46
大神们谁能告诉我应该刷什么题吗,我一道都没做出来,感觉工作无望了。
点赞
送花
回复
分享
发布于 2018-08-12 20:36
大佬帮看下我的代码有啥问题没?也是贪心的思想,不过并没有基于算导的那些公式; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Scanner; public class Main {     static class P implements Comparable<P>{         int a, b;         P(int c, int d) {             a = c;             b = d;         }         @Override         public int compareTo(P o) {             return a - o.a;         }         public String toString() {             return a + "," + b;         }     }     public static void main(String[] args) {         Scanner s = new Scanner(System.in);         int n = s.nextInt();         int m = s.nextInt();         List<P> list = new ArrayList<P>();         for (int i=0; i<n; i++) {             int a = s.nextInt(), b = s.nextInt();             if (a > b) b += m;             list.add(new P(a, b));         }         Collections.sort(list);         //System.out.println(list);         int cnt = 0;         List<P> r = new ArrayList<P>();         for (int i=0; i<list.size(); i++) {             if (r.size() == 0) { //第一个直接加入                 cnt ++;                 r.add(list.get(i));             } else if (list.get(i).a < r.get(r.size()-1).b) { //如果当前区间和已经加入的区间冲突那么就不加入                 //System.out.println(list.get(i) + "," + r.get(r.size()-1));                 continue;             } else {                 r.add(list.get(i));                 cnt ++;             }         }         System.out.println(cnt);         s.close();     } } 最后通过了33.33%,我也没注意到只能是当天收看这个条件,是不是还有其他问题?求教。
点赞
送花
回复
分享
发布于 2018-08-12 20:53
请问第四题20%那种方法,提示“存在数组越界非法访问等情况”,这个反馈意思是什么意思?
点赞
送花
回复
分享
发布于 2018-08-13 10:08
第五题似乎有问题呀。我自己看感觉是看懂你的思路,但是你的代码细节应该有问题。 我理解的思路是 每次选一个做开始节目,然后根据选择第一个节目的时间进行调整最后的期限(也就是和其他不同的地方所在),不满足期限直接break。第一个j表示开始的节目,第二个i表示从j开始的节目算起的节目数。   不知道我的理解对不对? 然后就是 3  10 0 3 3 7 7 0 return 3 这个测试用例就没通过。
点赞
送花
回复
分享
发布于 2018-08-13 10:34

相关推荐

点赞 70 评论
分享
牛客网
牛客企业服务