gcm 2018-08-04
一面
两个几十TB的文件,是否是一样的文件,该怎么判断?文件中每一行的数据一样但顺序不一样也是一样的文件。
答:正常的比较是将两个文件先按行排序,然后一行一行的比较下去。但是文件太大,比较次数太多了。
有一种数据结构可以去除顺序的影响,那就是HashMap,将每一行数据存在HashMap中,然后再遍历,依次比较。
大文件的操作一般都使用分治法。我给的答案是,两个大文件的每一行分别计算Hash值,Hash值前4位相同的都存到同一个以前4位命名的文件中。这样的话,总共有 16
4
=65536
164=65536 个文件,由于Hash离散性非常强,一个文件在1GB左右。已经可以在当前的机器上进行处理了。这样再使用HashMap存进去比较。所有文件比较完了都一样,才能说明两个几十TB的文件,是一样的文件。
然后问面试官这样可以吗?面试官说,你得分析时间复杂度和空间复杂度。然后我就分析了一下。
给1亿条边,这些边可以组成森林,问有多少颗树?
答:先和面试官确认边是怎么给的,(a,b)这样的形式吗?面试官说都可以。
正常情况下,需要先把这些边构建成树,然后判断有多少颗树。构建树的时候需要先找到之前的森林中有没有a顶点,有的话接上去,没有的话,自己造一棵树。这样的话时间复杂度太高了。
由于前面有过HashMap的经验,我想先把边以a为key存起来。这样判断森林中有没有这个顶点就会快很多。
问题还没有解决,但是时间已经来不及了,面试官又开始问后面的问题了。
最后回来想了一下,应该可以这样。先生成成千上万个以起点a命名的文件,文件名为a,文件内容为b的集合。a放在Hash表中,这样找起来会快很多。然后开始遍历每个文件的内容。比如说遍历到b了,就找所有以b命名的文件,然后将b的内容合并到a中去,将b删除,继续遍历a的内容,直到遍历完,第一个树就构造完成了。然后继续遍历下一个没有被合并的文件。等所有文件合并完成后,就知道有几颗树了。这样的话,相当于只保存了所有树的顶点和叶子节点,并不关心树的具体结构,最终得到了想知道的答案。
看你简历上会的东西挺多的,有没有专一的地方,未来的规划是什么,愿不愿意做运维。
答:可以做运维开发,单纯做运维,运营,测试,以后的路太窄了。
二面
40个有编号的球中选择6个出来,有多少种情况。
答:C
6
40
C406
将一个文件分成10个小文件。10个小文件分布在不同的机器上,每个机器最多只有一个小文件。现在有100台机器,一个机器出故障的概率为p,求这个文件的故障率。
答:文件的故障率=1-文件正常的概率
1−C
10
100
(1−p)
10
1−C10010(1−p)10
接上,现在有一种技术,一个文件分成10个小文件和3个校验文件。这13个文件中,只要有10个是正常的,文件都能恢复成功。问文件出故障的概率。
答:文件的故障率=1-(小文件都正常+一个小文件故障+两个小文件故障+三个小文件故障)
1−C
13
100
((1−p)
13
+C
1
13
p(1−p)
12
+C
2
13
p
2
(1−p)
11
+C
3
13
p
3
(1−p)
10
)
1−C10013((1−p)13+C131p(1−p)12+C132p2(1−p)11+C133p3(1−p)10)
看过哪些书?
答:《深入Java Web核心技术原理》,《HTML指南》,《设计模式》。
JVM原理
答:有很多有名的JVM,但我们最常用到的就是Oracle收购的sun公司的HotSpot。
HotSpot中内存被分为3个代:年轻代(young generation),年老代(old generation),持久代(permanent generation)。
get和post的区别
答:Get是向服务器发索取数据的一种请求,而Post是向服务器提交数据的一种请求,在FORM(表单)中,Method默认为”GET”,实质上,GET和POST只是发送机制不同,并不是一个取一个发。
观察者模式
答:有时被称作发布/订阅模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
有没有女朋友
答:没有。
微信公众号,微信支付
答:面试官之前研究过微信公众号一段时间,我简要介绍了一下我做过的一个微信商城。
XBox One
答:面试官家里有一个XBox 360。交流了一下XBox的体感游戏和经典游戏。
家庭情况
答:父母有兄弟姐妹照顾,没有后顾之忧。
兴趣爱好
答:羽毛球,乒乓球,玩游戏,写程序。
除了给公司开发项目之外,自己有没有做出过一些小工具
答:做过一个CSDN美化插件。
一面
自我介绍
答:balabala。
写二分查找算法
答:手写算法。
public static int rank(int goal, int[] data)
{
int start = 0;
int end = data.length - 1;
while (start <= end)
{
int mid = start + (end - start) / 2;
if (goal<data[mid])
{
end=mid-1;
}else if (goal>data[mid])
{
start=mid+1;
}else
{
return mid;
}
}
return -1;
}
判断单向链表有环
答:使用两个slow, fast指针从头开始扫描链表。指针slow 每次走1步,指针fast每次走2步。如果存在环,则指针slow、fast会相遇;如果不存在环,指针fast遇到NULL退出。
TCP协议三次握手,四次挥手
答:画了两张图。
Linux常用命令
答:cd,ls,cp,mv,mkdir,rm,pwd,rz,sz。
HashTable,HashMap,ConcurrentHashMap的区别。从底层实现上分析。
答:HashMap线程不安全,ConcurrentHashMap较安全,HashTable线程安全。
HashMap没有同步锁,HashTable对整个Hash表加锁,ConcurrentHashMap分段加锁。
擅长的语言
答:Java。
实习公司,做哪些工作.
答:Kingsoft。做过代码有效行数统计工具,多线程下载文件。
MapReduce的原理
答:讲了一下下面这张图的过程。
有没有想问的?
答:想了解一下这个岗位一天正常的工作是什么样的。面试官说运维开发,一半的时间开发,一半的时间运维。
对运维的理解
答:运维自动化,出错报警,自动修复,及时响应,7x24小时待命。面试官说会有轮班制,不会一年到头都神经绷紧。
二面
自我介绍
答:balabala。
滑动窗口有过了解吗
答:没有了解过。
TCP三次握手,4次挥手
答:画了一面的图。
端口号在哪一层,IP地址在哪一层
答:端口号在传输层,IP地址在网络层。
交换机和路由器的区别
答:交换机每个端口都可以设独立IP,路由器只能有一个独立IP,然后是局域网IP地址。
归并排序
答:手写归并排序。
public static int[] sort(int[] nums, int low, int high)
{
int mid = (low + high) / 2;
if (low < high)
{
// 左边
sort(nums, low, mid);
// 右边
sort(nums, mid + 1, high);
// 左右归并
merge(nums, low, mid, high);
}
return nums;
}
public static void merge(int[] nums, int low, int mid, int high)
{
int[] temp = new int[high - low + 1];
int i = low;// 左指针
int j = mid + 1;// 右指针
int k = 0;
// 把较小的数先移到新数组中
while (i <= mid && j <= high)
{
if (nums[i] < nums[j])
{
temp[k++] = nums[i++];
}
else
{
temp[k++] = nums[j++];
}
}
// 把左边剩余的数移入数组
while (i <= mid)
{
temp[k++] = nums[i++];
}
// 把右边边剩余的数移入数组
while (j <= high)
{
temp[k++] = nums[j++];
}
// 把新数组中的数覆盖nums数组
for (int k2 = 0; k2 < temp.length; k2++)
{
nums[k2 + low] = temp[k2];
}
}
希尔排序
答:手写希尔排序。
int[] a = { 49, 38, 65, 97, 76, 13, 27, 49, 78, 34, 12, 64, 1 };
System.out.println("排序之前:");
for (int i = 0; i < a.length; i++)
{
System.out.print(a[i] + " ");
}
// 希尔排序
int d = a.length;
while (true)
{
d = d / 2;
for (int x = 0; x < d; x++)
{
for (int i = x + d; i < a.length; i = i + d)
{
int temp = a[i];
int j;
for (j = i - d; j >= 0 && a[j] > temp; j = j - d)
{
a[j + d] = a[j];
}
a[j + d] = temp;
}
}
if (d == 1)
{
break;
}
}
System.out.println();
System.out.println("排序之后:");
for (int i = 0; i < a.length; i++)
{
System.out.print(a[i] + " ");
}
快速排序
答:手写快速排序。
private static void quick(int[] a)
{
if (a.length > 0)
{
quickSort(a, 0, a.length - 1);
}
}
private static void quickSort(int[] a, int low, int high)
{
if (low < high)
{ // 如果不加这个判断递归会无法退出导致堆栈溢出异常
int middle = getMiddle(a, low, high);
quickSort(a, 0, middle - 1);
quickSort(a, middle + 1, high);
}
}
private static int getMiddle(int[] a, int low, int high)
{
int temp = a[low];// 基准元素
while (low < high)
{
// 找到比基准元素小的元素位置
while (low < high && a[high] >= temp)
{
high--;
}
a[low] = a[high];
while (low < high && a[low] <= temp)
{
low++;
}
a[high] = a[low];
}
a[low] = temp;
return low;
}
二叉树,平衡二叉树,B树,B+树,红黑树
答:没有讲出来每种树的具体区别。
一颗二叉树,叶子节点有5个,度为1的节点有50个,问这棵二叉树总共有多少个节点
答:这里用到一个公式,但是我不记得了,只能手画出来,给出答案。
判断单向链表有环
答:还是一面的答案。
给栈增加一个方法,返回栈中第二大的元素,时间复杂度为O(1)
答:当时没有想出来。
回来之后想了一下,可以这样做。设置一个辅助栈,辅助栈中存第二大的数,但是还要有两个变量来存最大的数和第二大的数,这样出栈和入栈的时候可以方便比较,及时更新辅助栈。
TCP/IP协议栈各层
答:物理层,数据链路层,网络层,传输层,应用层。
常用Linux命令
答:面试官问了一些命令,问我是什么作用,我都不知道。
JVM内存模型及垃圾回收机制,Min GC,Full GC
答:新生代,老生代,永久代。
新生代 GC(Minor GC):指发生在新生代的垃圾收集动作,因为 Java 对象大多都具备朝生夕灭的特性,所以 Minor GC 非常频繁,一般回收速度也比较快。
老年代 GC(Major GC / Full GC):指发生在老年代的 GC,出现了 Major GC,经常会伴随至少一次的 Minor GC(但非绝对的,在 ParallelScavenge 收集器的收集策略里就有直接进行 Major GC 的策略选择过程) 。MajorGC 的速度一般会比 Minor GC 慢 10倍以上。
虚拟机给每个对象定义了一个对象年龄(Age)计数器。如果对象在 Eden 出生并经过第一次 Minor GC 后仍然存活,并且能被 Survivor 容纳的话,将被移动到 Survivor 空间中,并将对象年龄设为 1。对象在Survivor 区中每熬过一次 Minor GC,年龄就增加 1 岁,当它的年龄增加到一定程度(默认为 15 岁)时,就会被晋升到老年代中。对象晋升老年代的年龄阈值,可以通过参数 -XX:MaxTenuringThreshold 来设置。
网络编程,socket
答:写过一个QQ聊天程序,建立连接,发送或接收数据,释放连接。
并发包下的信号量
答:java.util.concurrent这个包下面的信号量Semaphore,可以允许多个线程同时访问。但是我对这个包没有怎么用过,了解的不多。
spring的@resource和@autowired
答:@resource默认按名称,@autowired默认按类型装载bean。
nginx做负载均衡器
答:我用过apache做过负载均衡器,面试官说公司用nginx做负载均衡器,我没有了解过,但是回去后会看一下怎么用的。
spring两大特性的理解及底层实现
答:spring的两大特性是IoC和AOP。IoC依赖注入,可以使代码解耦,将bean的生命周期交给容器管理。底层使用Java的反射机制来实现的。
AOP面向切面编程,可以实现事务,权限,日志等功能的统一实现,使代码进一步的解耦。底层使用代理模式实现的。
MySQL计划执行有用过吗?
答:我问面试官是说数据库的定时任务吗?面试官说不是。
后来查了一下,是用来查看SQL语句的执行情况的,然后进行性能分析用的。
看你用过Hibernate,MyBatis有用过吗?
答:没有用过,回来后会看的。
回来后研究了一下,可以参考这篇文章。
有看过一些开源项目的源码吗?
答:Java中的一些常用数据结构会看一下源码是怎么实现的。其他的开源项目大多停留在会用的层面。
HashTable,HashMap,ConcurrentHashMap的底层区别?
答:HashMap线程不安全,ConcurrentHashMap较安全,HashTable线程安全。
HashMap没有同步锁,HashTable对整个Hash表加锁,ConcurrentHashMap分段加锁。
HashMap中key可不可以为null,存在哪里?
答:没有了解过,因为平时用的时候没有存过key为null的对象。
回来后我看了一下JDK的源码。
其中有一段是这样的。int hash = (key == null) ? 0 : hash(key); 可以看出当key为null的时候,hash为0,所以当key为null的时候,存在第一个位置上。
final Entry<K,V> getEntry(Object key) {
if (size == 0) {
return null;
}
//重点是这一句
int hash = (key == null) ? 0 : hash(key);
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
if (key == null)
return putForNullKey(value); //重点这一句
int hash = hash(key);
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
private V putForNullKey(V value) {
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
if (e.key == null) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(0, null, value, 0);//重点这一句
return null;
}
队列里面放的有任务,每个任务的执行时间不一样,怎么让时间在前的任务先执行?
答:这样的话,可以用一个辅助的队列来找到时间在前的任务。
一面
Java8 的新特性
答:没有了解过。
JRE的指令有了解过吗?
答:Java代码编译成字节码之后的那种指令吗?没有了解过。
AOP的原理底层代码如何实现?
答:代理模式实现的。
但是我们写代码时,并没有使用代理模式,Spring是如何做到的?
答:我没具体了解过,可能是Spring改了原来的代码,然后用Java的反射机制加载新的代码。
synchronized和lock的区别
答:synchronized是Java的关键字,用于多线程的同步锁,synchronized范围结束自动释放掉。lock是java.util.concurrent包下面的类,手动加锁,手动释放。
实现生产者消费者原理
答:有一个资源池。然后有很多生产者线程,很多消费者线程,生产者往资源池里面放资源,消费者往资源池里面取资源。放资源和取资源都需要加同步锁。如果资源满了,生产者就sleep一段时间后再生产,资源池没有资源了,消费者就sleep一段时间后再消费。
不用sleep可以做到这个效果吗?
答:不用sleep的话。如果资源满了,调用对象的wait()方法等待。然后另一边的消费者消费了就调用对象的notify()方法唤醒线程。同理资源池没有资源了,消费者线程就调用对象的wait()方法等待,知道有生产者生产资源了唤醒消费者线程。
一组数,求出乘积最大值的连续几个数
答:动态规划法,缓存之前存储的最大的连续数的序列和乘积值,和新的不断试探的值进行比较,遇到乘积序列在 −1<x<1
−1<x<1 范围内直接放弃。
二面
自我介绍
答:balabala。
MapReduce的问题在哪儿?
答:map和reduce之间有combine和partition的过程。这个地方比较耗时间。
HDFS的原理和底层实现
答:有一张元信息表存储block的信息,block存储实际的文件,分布在各个节点。只会用,没有看过底层实现。
未来职业规划
答:技术专家路线。
Spring的特性
答:IoC和AOP。
注解方式找对象的实现原理
答:Java的反射机制可以获取类的属性和方法等信息,然后初始化这个对象。
为什么使用Bootstrap
答:可以实现响应式页面,降低前端门槛。
9月14日笔试,9月20日拿到Java开发的Offer。总共有1次笔试+一次电话面试+三次现场面试。下面记录一下我的经历,希望能为后来人提供经验。
①笔试
9月14日下午2:30去的公司。HR为我准备了一套试卷,要求在1小时内做完。难度不大,都是基础题,有几道记忆比较深的题,记录一下。
1.给出一段英文句子。要求将英文句子逆序输出来。例如“I’m a boy, she is a girl.”输出”. girl a is she , boy a I’m”。
解析:如果中间全是空格的话,直接使用split方法得到一个数组,然后将数组从后往前输出来就可以得到结果。但是现在中间有标点符号,还是要老老实实的一个单词一个单词的去判断,然后放进栈中,再输出来。
判断的方法,就是要使用两个指针,后面的指针指向单词的首字母,前面的指针找到空格,或者标点符号,就能判断单词的下标,然后就能把单词和标点符号压入栈中。还有就是要细心,考虑各种边界问题。连续遇到几个空格,几个标点符号都是有可能的。
2.给定一个数据库的表Test,表的内容如图所示。
idclassscore1one912one923two934two94
要求写出一个SQL语句,得到如下的结果。
onetwo22
解析:看题目应该就知道要使用聚集函数count来实现。但是我们如果写
select class ,count(id) from test group by class
得到的结果应该是这样的。
classcount(id)one2two2
很明显,这是一个行转列的问题。当时没有写出来。回来查了资料之后,应该这么写。
select distinct
count(case class when 'one' then 1 else 0 end) one,
count(case class when 'two' then 1 else 0 end) two
from test
group by class
运行之后,就会得到题目要求的结果。Oracle数据库的话有一个内置的pivot函数可以直接实现行转列,SQL Server数据库也有类似的函数。
但是虽然可以实现这种效果,扩展性几乎没有,下次还有一个three班级的话,又要改SQL语句。所以在实际应用中还是正规的查询出来数据,在代码中实现自己想要的结果吧。
3.专业名词解释。
解析:这个主要就是看一下知识的广度了。没什么好说的。
其他的都比较容易,也没什么好说的。
② 一面技术面
试卷做完之后,交上去之后,面试官就拿着一张表格来面试,上面有很多基础问题。
先让自我介绍,然后照着表格上的问题,一路问下来。很多问题有答案了,就不会深入问下去。都比较容易,问你对IoC和AOP的理解,Web容器的优化等等。
问你有没有什么想问面试官的,问了一下公司的情况和这个岗位的情况。
③二面技术面
一面面完之后,过了一个小时,深圳的面试官电话面试,还是技术面。
先让自我介绍,然后对做过的项目中的技术进行详细的了解。然后得出的结论就是我学习的Struts2已经过时了,他们已经在用SpringMVC了。继续问一些内存的优化技术,数据库的优化技术,等等。
问你有没有什么想问面试官的,问了一下公司的情况和这个岗位的情况。
④三面HR面
中间周六周日,没有什么动静了,然后周一来电话,通知终面。面试官应该是HR。
先让自我介绍,然后聊做过的项目,实习在哪里,和技术没什么关系。最后终于聊到薪酬了。问期望的薪酬。我报了一个数,HR自己也拿不定。又喊来一个同事,又面了一次技术面。
⑤四面技术面
四面面试官貌似级别更高了一点。
先让自我介绍,然后问我JVM的优化,数据库的优化,Web容器的优化,CDN的原理,集群方面的经验,MapReduce的原理,Redis有没有使用过,有没有使用过队列来削平访问高峰,压力测试自己的项目可以承受多大的并发量,有哪些优化措施。技术方面没有多大问题了,又开始聊薪酬和公司发展前景以及个人规划,最后可能我要价太高,面试官还是决定不了薪酬。
就先让我回去等消息,他们再商量一下。
⑥收到Offer
最终,还是收到Offer,但是薪酬和自己预期的还是有一些落差。
感谢一直奋斗的自己,感谢三之乐各位面试官抽出时间给我面试机会,让我能够发现自己的不足,并不断进步。
上面的5个公司都没有去,签了其他的公司。