金三银四跳槽季面经(一)主要和大家分享了B站推荐算法工程师的面经,今天和大家分享下笔者在小红书的面经。相比于金三银四跳槽季面经(一)中非LeetCode原题占比较大的情况,小红书的题目基本都是LeetCode原题,其中一道medium题,一道hard题。
小红书
坐标:黄浦区新天地
面试岗位:推荐算法工程师
面试形式:视频面试
面试难度:☆☆☆☆
小红书是视频面试,由于笔者比较着急,因此三轮视频面试在三天内全部搞定。
一面:小红书属于不按套路出牌的公司,一面面试官居然是推荐组的负责人。面试官开始也解释了一下原因,说这是他们最新的招人模式,先由他面试,如果工作经验不合适的话,直接挂掉,避免浪费双方的时间。然后就说我的简历和他们的岗位比较合适,希望我能够加入。接着就大致聊了下简历里面的项目,主要是MIND模型相关的改进以及GraphEmbedding的优化聊得比较多,面试官似乎对这两块更感兴趣。在之前的《MIND多兴趣召回实战(一)》,《GraphEmbedding实战(三)》两篇文章中,我有做过详细的介绍,感兴趣的读者,可以自行查阅。最后面试官说,后面会有组内的两位同事来面我,不会很难,期待我的加入。
二面:面试官不苟言笑,上来先写道题LeetCode210(课程表II)。一道中等难度题,这里附上代码解答:
class Solution {
// 存储有向图
List<List<Integer>> edges;
// 标记每个节点的状态:0=未搜索,1=搜索中,2=已完成
int[] visited;
// 用数组来模拟栈,下标 n-1 为栈底,0 为栈顶
int[] result;
// 判断有向图中是否有环
boolean valid = true;
// 栈下标
int index;
public int[] findOrder(int numCourses, int[][] prerequisites) {
edges = new ArrayList<List<Integer>>();
for (int i = 0; i < numCourses; ++i) {
edges.add(new ArrayList<Integer>());
}
visited = new int[numCourses];
result = new int[numCourses];
index = numCourses - 1;
for (int[] info : prerequisites) {
edges.get(info[1]).add(info[0]);
}
// 每次挑选一个未搜索的节点,开始进行深度优先搜索
for (int i = 0; i < numCourses && valid; ++i) {
if (visited[i] == 0) {
dfs(i);
}
}
if (!valid) {
return new int[0];
}
// 如果没有环,那么就有拓扑排序
return result;
}
public void dfs(int u) {
// 将节点标记为搜索中
visited[u] = 1;
// 搜索其相邻节点
// 只要发现有环,立刻停止搜索
for (int v: edges.get(u)) {
// 如果「未搜索」那么搜索相邻节点
if (visited[v] == 0) {
dfs(v);
if (!valid) {
return;
}
}
// 如果「搜索中」说明找到了环
else if (visited[v] == 1) {
valid = false;
return;
}
}
// 将节点标记为已完成
visited[u] = 2;
// 将节点入栈
result[index--] = u;
}
}
题目写完之后,又让跑个测试用例,结果跑出来符合预期。面试官又问了下时间复杂度和空间复杂度。回答完之后,面试官还是比较满意的,后面简历也就是挑几个项目问了下,整体沟通很顺畅。
三面:面试官应该是位资深算法工程师了,重点和她探讨了下召回离线评估指标相关的内容以及特征重要性评估方法。另外她问了下粗排的做法,笔者也给她做了相关解题。感兴趣的读者也可以参考我之前的文章《广告粗排技术(一)》,《召回离线评估指标(一)》,最后还是code时间,LeetCode239(滑动窗口最大值)。一道困难题,这里附上代码解答,借助双端队列即可。
class Solution {
//双端队列,从头到尾,严格满足由大到小
//队列里面放入index,头部为窗口的最大值
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums==null||k<1||nums.length<k){
return null;
}
LinkedList<Integer> qmax =new LinkedList<Integer>();
int[]res=new int[nums.length-k+1];
int index=0;
for(int i=0;i<nums.length;i++){
while(!qmax.isEmpty()&&nums[qmax.peekLast()]<=nums[i]){
qmax.pollLast();
}
qmax.addLast(i);
if(qmax.peekFirst()==i-k){
//i-k过期的下标
qmax.pollFirst();
}
if(i>=k-1){
//窗口形成了
res[index++]=nums[qmax.peekFirst()];
}
}
return res;
}
}
题目写完之后,也是让跑个测试用例,结果跑出来符合预期。后面就是笔者问了下他们组里的技术栈之类的。
hr面:是位东北大哥,聊了挺多内容,问我有没有用过小红书,觉得小红书的推荐做的如何等。不过核心问题还是看机会的原因以及期望薪资之类的常规问题。
本文主要给大家介绍了小红书相关面经。
欢迎大家关注我的微信公众号:计算广告那些事儿,点击往期精彩菜单,里面有笔者最近3-4月份,在B站、小红书、得物、字节、虾皮、拼多多面经汇总哈