连续四天的面试,简单记录下。
xx一面:
1.简单说了项目。
2.算法题。一个大于内存的文件怎么排序,这种题一看到肯定就是外部排序,内部归并处理,当时阻塞在认为每次归并必须把整个归并段全部调入内存中,再进行归并排序。然后就没把思路放在归并排序了,想到了堆排序,假设一共n个数,每趟可以使用小堆选出最大的k个数,然后将最大k个数输出到外存中,然后将剩下n-k个数再次调入内存进行堆排序,继续选出k个数,输出到外存中,直到所有的数字全部筛选完。内部使用归并肯定比堆排序处理的IO次数少,所以效率要高。
3.找到这个大文件的中位数,快排加上外部排序。
4.Lock和synchronized的区别和实现。
5.Java文件流,IO和NIO。 这个比较有意思,传统Java的IO是阻塞的,面试官一直追问我线程被阻塞,线程在等什么,当时没理解他问题的目的,回答等文件被写入,重复问它在等什么,回答等java调用操作系统提供的接口…蜜汁尴尬,重复问题,原来是个操作系统相关问题,在等通道处理…
6.面试官给了些建议,多注重底层,他们不关心那些什么框架…
xx二面:
1.JVM,GC简单说下。
2.多线程接触过没,简单描述下你使用的场景。
3.闲谈,实习时间等。
zz一面:
1.面试官第一个问题就问有刷题么,平时在哪刷题。。。答只刷了三十道题。
2.项目介绍。
3.算法题链表操作,复杂度,代码实现。
对链表的重排序问题:
输入:L1 L2 L3 …Ln-1 Ln
输出:L1 Ln L2 Ln-1 L3 Ln-2…
面试期间,只给出了O( n2 )复杂度的解决方法,当时写的代码在边界上也没处理好,虽然面试官没看出来,但是回来上机验证还是有问题。下面是用递归解决的。代码如下:
ListNode op(ListNode root) {
if (root.next == null | root == null) return root;
ListNode pointer, fronter = null, target;
pointer = root.next;
target = root;
while (target.next != null) {
fronter = target;
target = target.next;
}
fronter.next = null;
root.next = target
if (target != pointer) {
target.next = op(pointer);
}
return root;
}
复杂度:每一次都会减少两个结点,假设有N个结点,第一次遍历N个结点,第二次遍历N-2个,第三次遍历N-4个…这是一个等差数列。套用等差数列公式,算出时间复杂度约为O( n24 )。
当时在面试中,想再优化问题,在稿纸上已经画出了一个链表,然后找到中间结点断开,当时思路还是卡在断开后,后面那一段链表还是从头开始到后面找,如果这样时间复杂度当然也是减少了,也只是增大了分母,但还是
n2
的复杂度。后来回来睡觉就想到了,可惜当时没有想到。把后一段链表逆置,然后前后两个链表进行交叉合并,最后形成的链表就是目的链表。找到中间结点设置两个指针,一个一次步长一个两步长,走到链表尾部即可找到中间结点,链表逆置可以采用头插法,这里采用递归方法逆置。以下面链表为例:
ListNode op2(ListNode root) {
if (root.next == null | root == null | root.next.next == null) return root;
ListNode pointer, pointer2, root2;
pointer = pointer2 = root;
//先找到中间结点,断成两个链表
while (pointer2.next != null) {
pointer = pointer.next;
pointer2 = pointer2.next;
if (pointer2.next != null)
pointer2 = pointer2.next;
}
root2 = pointer.next;
pointer.next = null;
//将后一半链表逆置
root2 = inverse(root2);
pointer = root;
pointer2 = root2;
ListNode tmp1, tmp2;
while (pointer != null && pointer2 != null) {
tmp1 = pointer.next;
tmp2 = pointer2.next;
pointer.next = pointer2;
pointer = tmp1;
pointer2.next = pointer;
pointer2 = tmp2;
}
return root;
}
//逆置链表
ListNode inverse(ListNode root) {
if (root.next == null | root == null) return root;
ListNode head = inverse(root.next);
root.next.next = root;
root.next = null;
return head;
}
复杂度:第一步找链表中间结点,需要遍历整个链表复杂度O(
n
),第二步,逆置后一段链表,复杂度O(
4.递归都可以用迭代完成么?
5.同步,异步,阻塞,非阻塞。概念没讲清楚。
6.面试官建议到算法呢,只有多刷题,校招时候得把基础课程都温习一遍。
xxhr面:
1.自我介绍。
2.项目介绍。
3.项目困难,怎么解决。
4.平时看什么书等。
5.职业规划。