头条秋招春招失败的思考
毕设交了一波初稿,总算回来填坑了。回头想想,不得不说头条面试反映了我的心境变化。
秋招后台岗
一面
记得有2个题,其中一个应该非常水的题,没啥印象了。
数组中乘积最大连续子数组
这个现在就是一眼的dp,只怪刷了那么多题的我还是刷题太少了。
- Old Solution
直接暴力是$O(n^3)$的,所以就显然的前缀积优化到$O(n^2)$
蓝儿因为有$0$,这里就会有些问题,为了避免除$0$要做一些处理
不过实际上只要乘了$0$这一段乘积就是$0$了,所以把所有$0$的位置抠出来就可以了
然后枚举每一段,就不会有事了,答案初始化为$0$就可以了,前提是有一个$0$。。 - New Solution
很简单的dp啊,,$f[i][0/1]:$=到$i$这个位置的连续乘积最大值/最小值
就是套用最大连续子段和的套路,这破题我还被问过两遍
$HR$又做了一个更复杂的的树形的,不过那个时候我一眼秒了。。
就因为有负数嘛,所以就简单的维护下最小值就好了。。
二面
写个类似单调栈的玩意儿
印象中应该让写了一个支持push
,pop
,getMin
的栈,所有操作$O(1)$
- Solution
这东西也很简单啊,就维护数字栈的之后再顺手维护一个单调栈,细节注意一下就好了
我当时并没有想到单调栈,可能平时用的不多。不过还是有脑子的,随便一想就想到了。
我记得这个破题剑指offer上有吧,虽然一直没注意。
微信怎么拉取朋友圈信息
这东西我真不会啊,就xjb说了一下,本地存个跟帐号有关的hashvalue表示已经拉取了多少
每次拉取的时候,服务器也生成一个,比对一下,不适最新的就拉取就好了。
当然你问我什么别人点赞评论啥的,我真的不会啊。。
服务器很少,流量很大,怎么负载均衡啊
不会啊,xjb扯淡啊,就随手说了一下缓存服务器,Nginx啥的(这东西我tm就听过名字。讲道理啊,为啥不买设备啊喂!(大雾
三面
哇,这面跑不了啊,直接就问我后台技术栈啥的。
骗不过去了啊。然后就不知道啊。有点绝望啊。
意识不清醒了啊,打完比赛找不到工作一同交织在一起啊。
然后面试官问我读不读研啊。然后脑子一抽说想读啊。
然后我还耿直的去问头条有没有quit工作去读研啊没见过比我更sb的人了
主要还是比赛打炸了,心态太差了。几个月都没调好。
然后就没然后了啊
春招算法岗
一面
扯扯淡啊,自我介绍啥的啊,ACM打的怎么样啊。。
二叉树最长路径长度
一看就当普通树做了啊,然后就无脑说两次dfs求直径就好了啊。
他说能不能一次啊,那就无脑dp求一下直径啊。
他说还能不能再简单一点啊。 (dp还不简单啊
哇 我又看了一下题,发现二叉树。
然后我就说那简化一下啊。
- Code
struct Node{
Node* ls, *rs;
};
const int INF = INT_MAX / 2;
int maxd = -INF;
int dfs(Node* cur){
if(cur == nullptr) return 0;
int ldep = dfs(cur->ls);
int rdep = dfs(cur->rs);
maxd = max(maxd, ldep + rdep + 1);
return max(ldep, rdep) + 1;
}
脑筋急转弯
有25个人,跑道一次只能跑5个人,问最少跑几次能得到冠亚季军啊。
- Solution
一眼看穿是多路归并啊,然后算了一下是8啊。。
二面
不记得问了啥啊,就扔了一个题,然后问了点儿机器学习的东西
复杂链表的复制
Description
有一个链表L,其每个节点有2个指针,一个指针next指向链表的下个节点,另一个random随机指向链表中的任一个节点,可能是自己或者为空,写一个程序,复制这个链表Solution
剑指offer上有啊,看了一眼思路啊当时就,然后很慌啊。
不过面了那么多面试啊,一下子就冷静了啊。然后就会了啊。
就后面拷贝一份搞一搞啊。Code
struct Node{
int val;
Node *nxt, *random;
Node(){}
Node(int val, Node *nxt, Node *random): val(val), nxt(nxt), random(random){}
};
Node* copyComplexList(Node *head){
if(head == nullptr) return nullptr;
for(Node *cur = head; cur != nullptr; cur = cur->nxt->nxt){
Node *copied = new Node(cur->val, cur->nxt, cur->random);
cur->nxt = copied;
}
for(Node *cur = head->nxt; cur != nullptr; cur = cur->nxt->nxt){
cur->random = cur->random->nxt;
}
Node *nHead = head->nxt;
for(Node *cur = head; cur != nullptr; cur = cur->nxt){
Node *copied = cur->nxt;
Node *copiedNxt = copied->nxt->nxt;
Node *curNxt = cur->nxt->nxt;
cur->nxt = curNxt;
copied->nxt = copiedNxt;
}
return nHead;
}
机器学习
- 手推一下LR吧
就直接把Hypothesis Function,Cost Function写一写,Gradient Decent推一推啊。
然后我就推了一下啊,sigmoid函数的导数差点不会推啊。。有惊无险啊 - 正则参数$\lambda$选取的影响啊
大了会overfitting啊,小了会underfitting啊。
一个奇怪的题
Description
对一个数组,有n个数据,找一个索引的位置k,使前k个数的方差var(k)和后面n-k个数的方差var(n-k)之和最小。Solution
不知道能不能$O(1)$啊,不会做啊,就暴力展开了一下方差啊
然后$O(n)$枚举$k$,$O(1)$算答案,总复杂度$O(n)$Code
/*
var = \sum_{i=1}^n (x_i - avg)^2
= \sum_{i=1}^n (x_i ^ 2 + avg^2 - 2*x_i*avg)
= \sum_{i=1}^n (x_i ^ 2 + (sum / n)^2 - 2 * x_i * (sum / n))
= \sum_{i=1}^n x_i^2 + sum^2 /n - 2*sum^2/n= \sum_{i=1}^n x_i^2 - sum^2/n
*/
int findIndex(const vector<int>& v){
int preSqSum = 0, totSqSum = 0;
int preSum = 0, totSum = 0;
pair<double, int> varAndIdx = {-1, -1};
for(int i = 0; i < v.size(); ++i){
totSqSum += v[i] * v[i];
totSum += v[i];
}
for(int i = 0; i < v.size(); ++i){
preSum += v[i];
preSqSum += v[i] * v[i];
int sufSqSum = totSqSum - preSqSum;
int sufSum = totSum - preSum;
double preVar = preSqSum - 1.0 * preSum * preSum / (i + 1);
double sufVar = sufSqSum - 1.0 * sufSum * sufSum/ (v.size() - i - 1);
varAndIdx = max(varAndIdx, {preVar + sufVar, i});
}
return varAndIdx.second;
}
三面
24点游戏
Description
给定4个整数0~9,给出是否能计算得到24,加减乘除括号,普通算术运算。精度他说1e-5
Solution
以前写过啊,蓝儿没脑子了啊,连面了两面。
就选择写暴力搜索所有表达式啊。
然后就因为string v = "" + toChar(a) + toChar(b) + toChar(c) + toChar(d);
这个垃圾代码不CE挂了啊。。我以为会CE的啊。结果最后半天才反应到这里。
写了半个多小时,面试官他写了一个都写完了啊。。难受啊。。
我当时好怂啊,不自信啊。。结果面试结束后几分钟就调通了啊。My Code
找不到最终版本了,就扔个有点小问题的吧。纪念一下我这个“C++大师”
#include <bits/stdc++.h>
using namespace std;
const string op = "+-*/";
int getPriority(char c) {
if(c == '+' || c == '-') return 1;
else if(c == '*' || c == '/') return 2;
return 0;
}
vector<string> inToPost(const string& expr) {
stack<char> opr;
vector<string> ret;
for(int i = 0; i < expr.size(); ++i) {
char c = expr[i];
if(c == '(') opr.push(c);
else if(c == ')') {
while(true) {
char top = opr.top(); opr.pop();
if(top == '(') break;
ret.push_back(string(1, top));
}
} else if(isdigit(c)) {
string digit;
for(; i < expr.size() && isdigit(expr[i]); ++i) digit += expr[i];
ret.push_back(digit);
--i;
} else {
int curP = getPriority(c);
for(; opr.size() && getPriority(opr.top()) >= curP; opr.pop())
ret.push_back(string(1, opr.top()));
opr.push(c);
}
}
for(; opr.size(); opr.pop()) ret.push_back(string(1, opr.top()));
return ret;
}
double calc(const vector<string>& post) {
stack<double> opd;
for(const auto& s : post) {
if(isdigit(s[0])) opd.push(stod(s));
else {
assert(opd.size());
double y = opd.top(); opd.pop();
assert(opd.size());
double x = opd.top(); opd.pop();
if(s[0] == '+') opd.push(x + y);
else if(s[0] == '-') opd.push(x - y);
else if(s[0] == '*') opd.push(x * y);
else opd.push(x / y);
}
}
return opd.top();
}
bool check(int dep, bool lftBracketed, string s) {
if(dep == s.size()) {
if(lftBracketed) s += ')';
// cout << s << endl;
if(abs(calc(inToPost(s)) - 24) < 1e-5) return true;
return false;
}
if(isdigit(s[dep])) {
if(dep > 0) {
for(int i = 0; i < 4; ++i) {
string ns = s;
ns.insert(dep, 1, op[i]);
if(check(dep + 2, lftBracketed, ns)) return true;
if(lftBracketed) {
ns.insert(dep + 2, 1, ')');
if(check(dep + 3, 0, ns)) return true;
} else {
ns.insert(dep + 1, 1, '(');
if(check(dep + 3, 1, ns)) return true;
}
}
} else if(check(dep + 1, lftBracketed, s)) return true;
} else if(check(dep + 1, lftBracketed, s)) return true;
return false;
}
bool twentyFour(int a, int b, int c, int d) {
auto toChar = [](int x) {return char('0' + x);};
string v = string("") + toChar(a) + toChar(b) + toChar(c) + toChar(d);
sort(v.begin(), v.end());
bool ok = false;
do {
ok |= check(0, 0, v);
} while(!ok && next_permutation(v.begin(), v.end()));
return ok;
}
int main() {
string test = "5*5-5/5";
//cout << calc(test) << endl;
cout << (calc(inToPost(test))) << endl;
cout << twentyFour(5, 5, 5, 5) << endl;
return 0;
}
- Interviewer’s Code
没仔细读这个代码啊,改天研究一下正确性,写一个bugfree的24点感觉不容易啊。。
import itertools
def isEqual(v0, v1):
return abs(v0 - v1) < 1e-6
def expresssion(code, v0, v1):
if code == 0:
return v0 + v1
elif code == 1:
return v0 - v1
elif code == 2:
return v1 - v0
elif code == 3:
return v0 * v1
elif code == 4:
if isEqual(v1, 0):
return float('NaN')
return float(v0)/v1
elif code == 5:
if isEqual(v0, 0):
return float('NaN')
return float(v1)/v0
def printExpr(code, v0, v1):
if code == 0:
print '%s+%s' %(v0, v1)
if code == 1:
print '%s-%s' %(v0, v1)
if code == 2:
print '%s-%s' % (v1, v0)
if code == 3:
print '%s*%s' % (v0, v1)
if code == 4:
print '%s/%s' % (v0, v1)
if code == 5:
print '%s/%s' %(v1, v0)
def search(a, v):
if len(a) == 1:
return isEqual(a[0], v)
elif len(a) == 2:
for code in range(6):
if isEqual(expresssion(code, a[0], a[1]), v):
printExpr(code, a[0], a[1])
return True
return False
elif len(a) == 3:
for b in itertools.permutations(a):
for code in range(6):
if search([expresssion(code, b[0], b[1]), b[2]], v):
printExpr(code, b[0], b[1])
return True
return False
elif len(a) == 4:
for b in itertools.permutations(a):
for code in range(6):
if search([expresssion(code, b[0], b[1]), b[2], b[3]], v):
printExpr(code, b[0], b[1])
return True
return False
elif len(a) == 4:
for b in itertools.permutations(a):
for code in range(6):
if search([expresssion(code, b[0], b[1]), b[2], b[3]], v):
printExpr(code, b[0], b[1])
return True
return False
print search([3, 3, 8, 8], 24)
然后就又没然后了啊
后记
好好学习辣!然后要自信!失败了并不会失去什么。