字节跳动_暑期实习面试
时间:2020年6月29日--2020年7月10日
地点:线上
面试机会的取得
一、得知活动
是通过字节跳动“玩转客户端”活动得到的推荐获得的面试机会。
面试的经过
一、一面
时间:2020年6月29日 17:30
地点:线上
-
自我介绍/交流
-
聊比赛/训练经历居多
-
知识点考察
-
面试中的笔试题
输入英语句子,将单词逐个反转然后输出。
样例输入: Yummy! What is it made of?
样例输出: ymmuY! tahW si ti edam fo?
其实这是简单题了,在ACM的比赛中只是签到题的水平,但在面试的过程中还是有挺多需要讲究的。
-
面试时的代码
#include <iostream> #include <string> using namespace std; int main(){ string str; ios::sync_with_stdio(false); while(cin>>str){ int len = str.length(); if(str[len-1]=='!'||str[len-1]=='.'||str[len-1]==','||str[len-1]=='?'){ for(int i=len-2;i>=0;i--) cout<<str[i]; cout<<str[len-1]<<' '; } else { for(int i=len-1;i>=0;i--) cout<<str[i]; cout<<' '; } } return 0; }
-
其实上面的代码明显还是有很多问题的,首先我不能保证输入是规范的,我不知道标点符号后面是否一定会带空格。其次,英文的标点符号肯定是不止我所列举的这些。虽然说这与题目不够规范也有关系,但是面试出题者肯定也想考核我们思考问题的全面性。
-
面试后的改进
// 采用先进后出的栈结构,更符合此题的思路 #include <cstdio> #include <vector> using namespace std; bool isAlphabet(char c){ return (c>='a' && c<='z') || (c>='A' && c<='Z'); } int main(){ char c; vector<char> v; while(~scanf("%c",&c)){ if(c == '\n') break; if(isAlphabet(c)){ v.push_back(c); } else { while (!v.empty()) { printf("%c",v.back()); v.pop_back(); } printf("%c",c); } } return 0; }
-
二、二面
-
这次没有自我介绍
-
知识点考察
-
c++语法基础
智能指针/static const等关键字修饰函数的作用/volatile关键字/stl库底层源码实现
-
计算机网络
http协议的具体细节
-
-
面试中的笔试题
输入一个数字,输出其各位数字排列组合下一大的数
样例输入: 12654
样例输出: 14256
这个的思路就是从后往前找第一个小于最后一个数的数,然后把最后一个数插到它前面,并且对它后面的数进行升序排序。(这里的它都是指第一个小于最后一个数的数)
#include <algorithm> #include <iostream> #include <string> #include <set> using namespace std; #define setiter set<int>::iterator string findNxt(string a){ string temp; char back = a.back(); a.pop_back(); while(!a.empty()){ auto t = a.back(); temp.push_back(t); a.pop_back(); if(t<back) break; } a.push_back(back); a.push_back(temp.back()); temp.pop_back(); sort(temp.rbegin(), temp.rend()); while(!temp.empty()) { a.push_back(temp.back()); temp.pop_back(); } return a; } int main(){ string str = "12654"; cout<<findNxt(str)<<endl; return 0; }
三、三面
-
自我介绍
-
知识点考察
- c++语法基础
- 计算机网络
-
聊实际应用中的前端浏览体验改善
-
聊之前的项目做了什么,有什么还要改进的地方
-
面试中的非笔试题
25匹马,5个跑道,每次只能跑5匹,用最少的次数选出最快的前3匹?
(备注:没有秒表,只能知道马的先后顺序)
这道题我以前是没有接触过的,所以只能临场发挥,还好最后还是回答上了正确答案。
Step 1:
把马随机分成5组,每组5匹,分别进行赛跑,共需5次
Step 2:
取前5次比赛各自的第1名出来,组成1组,进行赛跑,共1次
Step3:
取Step2那次比赛的第2名和第3名、第1名在Step1所在的组的第2名和第3名、第2名在Step2所在组的第2名,组成1组,进行赛跑,共1次
所以总共7次可以选出最快的前3匹
-
面试中的笔试题
输入两个链表,一个升序、一个降序,合并成一个升序链表。
样例输入: 2->6->8->9、10->7->3
样例输出: 2->3->6->7->8->9->10
其实这挺简单的,就是链表不熟悉,所以没有答上来,后来还是面试官换了一道题。面试后的补题:
#include<iostream> using namespace std; struct Node{ Node* next = NULL; int value = 0; }; Node* ReadALink(int m) { bool isHead=1; Node *head,*newp,*oldp; newp = oldp =new Node; cin>>newp->value; head = newp; while(m--){ if(isHead) isHead = 0; else oldp->next = newp; oldp = newp; newp = new Node; cin>>newp->value; } oldp->next = newp; newp->next = NULL; return head; } Node* ReverseALink(Node* head) { if (head == NULL || head->next == NULL) return head; Node *newhead = head, *nxt = head->next; newhead->next = NULL; while(nxt != NULL) { Node *iter = nxt-> next; nxt->next = newhead; newhead = nxt; nxt = iter; } return newhead; } Node* MergeLinks(Node* head1,Node* head2) { Node *p,*newhead=NULL,*t=new Node; while(head1&&head2) { if(head1->value<head2->value) { p=head1; head1=head1->next; } else { p=head2; head2=head2->next; } if(!newhead) newhead=t=p; else{ t=t->next=p; p->next=NULL; } } t->next = head1?head1:head2; return newhead; } int main(){ int m,k; cin>>m>>k; Node* headup = ReadALink(m-1); Node* headdown = ReadALink(k-1); Node* headnew = ReverseALink(headdown); Node* ans = MergeLinks(headnew,headup); while(ans->next != NULL){ cout<<ans->value<<' '; ans = ans->next; } cout<<ans->value<<endl; return 0; }
输入一个数组,找到所有合为100的组合,数字重复的组合不算,询问组合数量。
样例输入: 1 2 3 3 27 97 97 99 100
样例输出: 2
这道也是简单题,但是后来面试官问我怎么优化空间复杂度的时候我脑子没有转过来,直接回答那就两个for循环吧。先给出面试时的代码:
#include<iostream> using namespace std; int findAndIsH(int* a,int len){ bool vis[101] = {0}; bool find[101] = {0}; int cnt = 0; for(int i=0;i<len;i++){ if(vis[a[i]]) continue; vis[a[i]] = 1; if(find[a[i]]){ cnt++; } else { find[100-a[i]] = 1; } } return cnt; } int main(){ int a[10] = {1,2,3,3,27,97,97,99,100}; cout<<findAndIsH(a,9)<<endl; return 0; }
后来改的代码(优化了时间复杂度),在修改的过程中我还发现了上面的做法还有一个问题,就是如果是50、50就考虑不到了:
#include <iostream> #include <cstring> #include <set> using namespace std; #define setiter set<int>::iterator int findAndIsH(int* a,int len){ set<int> s; // int cnt[51]={0}; int ans = 0; for(int i=0;i<len;i++){ s.insert(a[i]); } setiter l = s.begin(); setiter r = s.end(); while(l!=r) { if(*l == 100-*r){ ans++; l++; r--; } else if(*l < 100-*r){ l++; } else{ r--; } } /* for(set<int>::iterator iter=s.begin();iter!=s.end();iter++){ int re = *iter<50?*iter:100-*iter; cnt[re]++; } for(int i=0;i<51;i++){ if(cnt[i]>1) ans++; } */ return ans; } int main(){ int a[10] = {1,2,3,3,27,97,97,99,100}; cout<<findAndIsH(a,9)<<endl; return 0; }
由于在让我优化空间复杂时我扯了一下用map,然后就被考到了map的空间复杂度和map的底层实现。
-
聊自己的优点和缺点
面试的总结
虽然是凉经,当整体来说字节的面试过程还是很舒适的吧,相信只要简历不要写得太飘,应该就不会被重重地拷打一番。
然后说一下面试的等待时间吧。一面的结果等了大概一星期吧,二面的结果大概两天就出了,三面也是两天出了结果。
最后祝福大家可以面到想要的工作。