腾讯、百度、珍爱网、中国电信、三之乐面试经历

版权声明:本文为博主阿甘(Gane_Cheng)原创文章,欢迎转载,传播知识,请留言告知并注明出处,方便文章有误改正之后能找到原文。个人之言,请抱着怀疑的态度参考! https://blog.csdn.net/Gane_Cheng/article/details/54142709

这里写图片描述

2016年9月中下旬面试了5家公司。留下一点经验给后来人。

转载请注明出处:

http://blog.csdn.net/gane_cheng/article/details/54142709

http://www.ganecheng.tech/blog/54142709.html (浏览效果更好)

腾讯(运营开发)

一面


两个几十TB的文件,是否是一样的文件,该怎么判断?文件中每一行的数据一样但顺序不一样也是一样的文件。

答:正常的比较是将两个文件先按行排序,然后一行一行的比较下去。但是文件太大,比较次数太多了。

有一种数据结构可以去除顺序的影响,那就是HashMap,将每一行数据存在HashMap中,然后再遍历,依次比较。

大文件的操作一般都使用分治法。我给的答案是,两个大文件的每一行分别计算Hash值,Hash值前4位相同的都存到同一个以前4位命名的文件中。这样的话,总共有 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个出来,有多少种情况。

答: C640

将一个文件分成10个小文件。10个小文件分布在不同的机器上,每个机器最多只有一个小文件。现在有100台机器,一个机器出故障的概率为p,求这个文件的故障率。

答:文件的故障率=1-文件正常的概率

1C101001p10

接上,现在有一种技术,一个文件分成10个小文件和3个校验文件。这13个文件中,只要有10个是正常的,文件都能恢复成功。问文件出故障的概率。

答:文件的故障率=1-(小文件都正常+一个小文件故障+两个小文件故障+三个小文件故障)

1C13100(1p13+C113p1p12+C213p21p11+C313p31p10)

看过哪些书?

答:《深入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开发)

并发包下的信号量

答: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;
    }

队列里面放的有任务,每个任务的执行时间不一样,怎么让时间在前的任务先执行?

答:这样的话,可以用一个辅助的队列来找到时间在前的任务。


中国电信 IT 研发中心(Java开发)

一面


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 范围内直接放弃。


二面


自我介绍

答:balabala。

MapReduce的问题在哪儿?

答:map和reduce之间有combine和partition的过程。这个地方比较耗时间。

HDFS的原理和底层实现

答:有一张元信息表存储block的信息,block存储实际的文件,分布在各个节点。只会用,没有看过底层实现。

未来职业规划

答:技术专家路线。

Spring的特性

答:IoC和AOP。

注解方式找对象的实现原理

答:Java的反射机制可以获取类的属性和方法等信息,然后初始化这个对象。

为什么使用Bootstrap

答:可以实现响应式页面,降低前端门槛。


三之乐(Java开发)

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,表的内容如图所示。

id class score
1 one 91
2 one 92
3 two 93
4 two 94

要求写出一个SQL语句,得到如下的结果。

one two
2 2

解析:看题目应该就知道要使用聚集函数count来实现。但是我们如果写

select class ,count(id) from test group by class

得到的结果应该是这样的。

class count(id)
one 2
two 2

很明显,这是一个行转列的问题。当时没有写出来。回来查了资料之后,应该这么写。

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个公司都没有去,签了其他的公司。

猜你喜欢

转载自blog.csdn.net/Gane_Cheng/article/details/54142709
今日推荐