今日头条面试经验
今日头条面试经验
一共四轮面试 前三轮是技术面试,最后一轮是hr面试。
(我选的python语言)
第一轮:问了简历上的两个项目,简单的介绍了一下项目,问了一些项目里的技术问题。然后直接开始出题,在一张A4纸上写代码。(一个半小时)
第一题:给函数传递一个正整数的列表alist和一个正整数T,假装它等于[1,3,6,4,2,7],给出alist里所有相加等于T的元素的list,每个数只用一次。比如T=7,列表里3+4=7,7=7,1+6=7。你的函数就要返回[[3,4],[7],[1,6]]。
之前见过类似的题目,很快就给出了解题思路,我用的回溯法,但是这个代码对我而言有点复杂了,只能写出来整体的框架,递归调用的返回值想不明白。面试结束的时候,面试官说我三道题给出的算法都很优。
第二题:面试官给我讲了一下第一题应该怎么返回,大概明白了他的意思,但是还是不怎么会放到代码里,第二题是第一题的加强版。第一题中限定了每个数只出现一次,第二题不用限制。就是可以1+1+1+1+…=7,也可以2+2+3=7。其实和第一题超级像,只要改一个返回值就好,我告诉了面试官该怎么改第一题的代码,然后他让我写出来这个题的代码。嘤嘤嘤。。。。憋了很久,自己感觉还是不怎么对。回溯回溯。
第三题:用两个堆栈实现队列的push和pop功能。
我直接给出代码吧。
上面是我昨天面试写的代码。整体来讲就是用两个list来模拟堆栈,命名为alist,blist。push操作时,将数据存到alist里。Pop操作时,从blist里面pop。如果blist里为空,就把alist的数据全部转移到blist里。如果alist也为空,就pop失败。但是只有在blist为空时,才可以从a往里转移数据,不然就不能保证输出数据有队列的性质了。我也不知道怎么解释,稍微画画图模拟一下就很简单啦。
(代码还有漏洞,只希望能加深你们对这题的理解,望不吐槽代码小渣渣。)
(然后就觉得面试官对这题的答案贼满意,大概是挽回了前两题写不出代码的损失)
第二轮:先自我介绍了一下,然后什么也没问,直接开始写代码,不过感觉这个人主要关注了我的算法思想,第二题代码写了一半,有一个框架就没让我继续写了。(半个小时)
第一题:有那么n个列表,每个列表有不确定个>=0的数,没有排序(列表大概长这个样子[3,0,9,11,2…..]),现在要每个列表里面选出一个元素,分别为a1,a2….an .使得满足 a1<=a2<=a3<=….<.an 的基础上a1+a2+。。。。。+an的值最大。先解释你的算法思想并且说出你算法的时间复杂度,然后写出时间负责度。(补充,这n个列表的位置是固定的,第一个列表选出来的元素就是a1,第二个就是n2,不用考虑先选哪一个列表)
有了上一轮惨痛的体验,我就想安安稳稳的活着,用了一个最稳妥的方法,就是从an里选最大的,从an-1里选小于an而且最大的。在过程中可以判断一下是否可以提前结束就可以了。
第二题:有一条马路,马路上有很多树,树的高度不一。现在要统一剪树,剪到高度为h。意思就是,比h高的树都剪到h,比h低的树高度不变。所有的树剪掉的总长度为C。现在要使C>某个值的情况下(假设为MM),使h最大。问怎么确定h。
我用的二分法。初始min=0,max=最高的树,mid=(min+max)/2。在确定一个误差a,当误差小于某个数的时候就认为这个h是我们要的高度。
然后他问我 如果误差是十的-6次方,时间复杂度是多少 。。。。。。。。。。。。。。
第三轮:好像闯到了最后一关,到了主管面试环节,主管超级严肃,进来问了下什么时候可以入职,什么时候工作,一些很随意的问题,问了简历上两个项目,就又开始写代码。。。。。就一道题。(半个小时)
循环有序列表:[7,7,8,9,1,2,5,6,7,7],就是这个循环左移可以变成一个有序的列表。查找这个列表中是否有某个数,说出你的思路。
我第一个方法是遍历。如果大于list[0]就从前向后遍历。如果小于list[0]就从后向前遍历,被鄙视了。
第二个方法是二分法。如果要查找的数a小于list[mid],那么这个数一定在list[:mid]。如果要查到的数大于list[mid],分两种情况,如果大于list[0]则在左边,如果小于,则在右边。回答完感觉面试官露出了满意的笑容。这道题想了好久,一度觉得要自己要凉凉。
Hr面就很随意啦。我的hr也是一枚实习生,刚入职一个月。
一口气写下来 还没来得及检查,有错误请指正。然后自己确实比较菜,希望看这个的大佬们别嫌弃我太low。然后我的方法都是面试时候给面试官的,事后没有再百度,应该会有更好的算法思想的。你们再想想。。。。
看别人的面试经验,总之感觉不是很难。但是要在很短的时间讲明白算法的思想并且写出来也不是一件容易的事情。
这些题目大都是LeetCode上的。
1.1
40. Combination Sum II
package solutions._40;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 40. Combination Sum II
*/
class Solution {
private boolean[] visited;
private List> result = new ArrayList<>();
private List cur = new ArrayList<>();
private void DFS(int[] arr, int target, int pos, int sum) {
if (sum > target) {
return;
}
if (target == sum) {
result.add(new ArrayList<>(cur));
return;
}
for (int i = pos; i < arr.length; i++) {
if (visited[i]) {
continue;
}
if (i != 0 && arr[i] == arr[i - 1] && !visited[i - 1]) {
continue;
}
if (!visited[i]) {
visited[i] = true;
cur.add(arr[i]);
DFS(arr, target, i, sum + arr[i]);
visited[i] = false;
cur.remove(cur.size() - 1);
}
}
}
public List> combinationSum2(int[] candidates, int target) {
Arrays.sort(candidates);
visited = new boolean[candidates.length];
DFS(candidates, target, 0, 0);
return result;
}
public static void main(String[] args) {
Solution solution = new Solution();
int[] arr = {10, 1, 2, 7, 6, 1, 5};
List> list = solution.combinationSum2(arr, 8);
System.out.println(list);
}
}
1.2
39. Combination Sum
package solutions._39;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
* 39. Combination Sum
*/
class Solution {
private List> result = new ArrayList<>();
private LinkedList cur = new LinkedList<>();
private void DFS(int[] arr, int pos, int curSum, int sum) {
if (curSum > sum) {
return;
}
if (curSum == sum) {
result.add(new ArrayList<>(cur));
return;
}
for (int i = pos; i < arr.length; i++) {
cur.add(arr[i]);
DFS(arr, i, curSum + arr[i], sum);
cur.removeLast();
}
}
public List> combinationSum(int[] candidates, int target) {
DFS(candidates, 0, 0, target);
return result;
}
public static void main(String[] args) {
Solution solution = new Solution();
int[] arr = {2, 3, 6, 7};
int target = 7;
List> list = solution.combinationSum(arr, target);
System.out.println(list);
}
}
1.3
import java.util.Stack;
public class Solution {
Stack stack1 = new Stack();
Stack stack2 = new Stack();
public void push(int node) {
stack1.push(node);
}
public int pop() {
if (!stack2.isEmpty()) {
return stack2.pop();
}
while (!stack1.isEmpty()) {
stack2.push(stack1.pop());
}
return stack2.pop();
}
}
2.1
先从最有一个列表选择最大的,在从倒数第二个列表选择次大的,以此类推。
2.2
3.1
81. Search in Rotated Sorted Array II
在旋转数组中查找某个数是否存在。
所谓的旋转数组:
原数组:[0,1,2,4,5,6,7]
对应的旋转数组可以是:
[0,1,2,4,5,6,7]
[1,2,4,5,6,7,0]
[2,4,5,6,7,0,1]
[4,5,6,7,0,1,2]
[5,6,7,0,1,2,4]
[6,7,0,1,2,4,5]
[7,0,1,2,4,5,6]
一般的,原数组都是经过排序的。
可以发现,所谓的旋转数组对应了两个局部有序的数组。(先递增再递增)
当然也有特殊的情况。
仔细看看一个旋转数组 {4,5,1,2,3}, 不难发现如下特点:
/**
* 153. Find Minimum in Rotated Sorted Array
*/
class Solution {
public int findMin1(int[] nums) {
int i;
for (i = 1; i < nums.length; i++) {
if (nums[i] < nums[i - 1]) {
break;
}
}
if (i == nums.length) {
return nums[0];
}
return nums[i];
}
public int findMin2(int[] nums) {
int left = 0;
int right = nums.length - 1;
while (left < right) {
if (nums[right] > nums[left]) {
return nums[left];
}
int mid = left + (right - left) / 2;
if (nums[mid] >= nums[left]) {
left = mid + 1;
} else {
right = mid;
}
}
return nums[right];
}
public static void main(String[] args) {
Solution solution = new Solution();
int[] arr = {4, 5};
System.out.println(solution.findMin1(arr));
System.out.println(solution.findMin2(arr));
}
}