又到春招季了,小编相信,许多即将走出校园的应届生,都梦寐以求地想挤进企鹅、杭研、脸书等等大厂。尤其是贵邮的学子,更是深深的BAT和FLAG情结。因为,这些大厂不仅能提供一流的薪水和丰厚的package,还能提供理想的工作环境和神一样的队友。
那么问题来了,IT名企对应聘者有什么样的要求呢?以JavaWeb工程师为例,小编相信,对于Java基础、三大框架、数据库、Ajax、Linux等等常用技能,大家已经掌握的比较熟练了,但很多人依然有这么一个短板——数据结构与算法;甚至一些领域的专家,一不小心跪在某道面试题上面的事情,也常有发生。
这不,Homebrew的作者Max Howell就收到了谷歌的拒信:
90% of our engineers use the software you wrote (Homebrew), but you can’t invert a binary tree on a whiteboard so fuck off.
原贴链接:
https://twitter.com/mxcl/status/608682016205344768
程序测试地址:
https://leetcode.com/problems/invert-binary-tree/
这件事情在国内外各大社区也是炸开了锅,有兴趣的同学可以去twitter、知乎、v2ex等论坛讨论。
不会反转二叉树,十年经验也枉然!
废话不多说,我们直接来做题。题目非常简短,就一句话:反转二叉树,或者叫做二叉树的镜像。
把
变成
二叉树节点的定义如下:
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x;
}
}
其实就是交换所有的左右子树啊!先、中、后、层这四个无节操的模板,均可以毫无压力地解决这道题。
一、使用后序遍历模板,考虑根节点4:
1、假设左子树2和右子树7已经反转完毕,即:递归处理2和7
2、交换2和7,算法完成
代码:
public class Solution {
public TreeNode invertTree(TreeNode root) {
postOrder(root);
return root;
}
public void postOrder(TreeNode p) {
if (p != null) {
postOrder(p.left);
postOrder(p.right);
TreeNode temp = p.left;
p.left = p.right;
p.right = temp;
}
}
}
时间复杂度为O(N),空间复杂度为O(logN)。
二、使用先序遍历模板,考虑根节点4:
1、交换左孩子2和右孩子7
2、递归处理2和7,算法完成
代码:
public class Solution {
public TreeNode invertTree(TreeNode root) {
preOrder(root);
return root;
}
public void preOrder(TreeNode p) {
if (p != null) {
TreeNode temp = p.left;
p.left = p.right;
p.right = temp;
preOrder(p.left);
preOrder(p.right);
}
}
}
时间复杂度为O(N),空间复杂度为O(logN)。
1、递归处理左孩子2
2、交换左孩子2和右孩子7
3、递归处理左孩子7,算法完成
代码:
public class Solution {
public TreeNode invertTree(TreeNode root) {
inOrder(root);
return root;
}
public void inOrder(TreeNode p) {
if (p != null) {
inOrder(p.left);
TreeNode temp = p.left;
p.left = p.right;
p.right = temp;
inOrder(p.left);
}
}
}
时间复杂度为O(N),空间复杂度为O(logN)。
四、使用 层 序遍历模板 ,层序遍历需要借助于队列,在循环体当中,使用先交换、再入队,或者先入队、再交换两种策略均可,代码如下:public class Solution {
public TreeNode invertTree(TreeNode root) {
if (root == null) {
return null;
} else {
Queue queue = new LinkedList();
queue.offer(root);
while (!queue.isEmpty()) {
TreeNode p = queue.poll();
if (p.left != null) {
queue.offer(p.left);
}
if (p.right != null) {
queue.offer(p.right);
}
TreeNode temp = p.left;
p.left = p.right;
p.right = temp;
}
return root;
}
}
}
其实吧,写完以上四种算法就经很有逼格了,包括LeetCode官方也只给出了先序型的递归算法和层序型的非递归算法。其实下面一种算法是最牛X的,能秒杀谷歌Offer!
五、使用先序遍历非递归模板,借助于栈实现。最关键的步骤就是addLeft方法,将右孩子的最左边路径所经过的节点依次压栈,这样,弹栈顺序和先序遍历就是一模一样的,代码如下:
public class Solution {
private void addLeft(TreeNode p,Stack stack){
while(p!=null){
stack.push(p);
p=p.left;
}
}
public TreeNode invertTree(TreeNode root) {
TreeNode p=null;
Stack stack=new Stack();
addLeft(root, stack);
while(!stack.isEmpty()){
p=stack.pop();
addLeft(p.right, stack);
TreeNode t=p.left;
p.left=p.right;
p.right=t;
}
return root;
}
}
想不AC都难啊!
另外,数据结构与算法类面试题远远不止这一道,大家想要举一反三、融会贯通地应对名企面试,还需多翻一翻《编程之美》、《剑指offer》、《编程之法》等指导书,多刷一刷LeetCode、PAT等OJ,多搜一搜BAT和FLAG等公司的面经;熟练了之后,你会发现,考来考去,无非是数组、链表、字符串、栈和队列、二分查找、二叉树、矩阵、排序、并查集、堆、哈希、位运算、图论、贪心、分治、动态规划、NP完全......
当然,熟练掌握以上知识点,并不是一朝一夕的事情,总要有个过程,甚至有可能很艰辛,但为了进名企、为了遇到神队友、为了将来的高薪,何不拿出高三时候的勤奋与刻苦,趁年轻的时候拼一拼?
最后,小编是一个上升星座为白羊的男生,非常喜欢我司的打开IDE,更新GIT、写代码、编译运行、测试、提交、上线、发工资、拿年终奖这种简单粗暴的工作方式,什么Maven下载速度为10K/S、IDE注册码马上过期、VPN被禁、分页插件不兼容、中文乱码之类的问题,统统见鬼!所以,面试是个双向选择过程,应聘者需要通过面试官的提问判断职位是否适合自己,而各个大厂的面试题侧重点又稍有不同,大家要多看面经,选择匹配自己的公司和职位。比如:
1、阿里巴巴偏重业务和运营,所以算法题(除了某些特殊岗位之外)不会太难,但涉及面就非常广,设计模式、Linux、操作系统、DB、Spring原理等以及项目经验都会问到。像什么“Servlet生命周期、ClassLoader加载顺序、Spring和Struts的优缺点、TCP三次握手”之类的概念型面试题,感觉是在浪费生命,完全无爱啊!
2、腾讯的算法题难度中等,最典型的是2014年校招笔试,题量适中,质量也非常高,难怪许多人(包括小编在内)说互联网格局是TAB。
3、百度、谷歌、FB的少部分题目还挺虐心,已经远远超出了《剑指offer》的总体难度,不过仔细分析的话,并未超纲。
4、还有喜欢聊dota、聊动漫、聊网红、聊马哲的面试官,比如我司。
参考资料:
前中后层模板:http://www.jikexueyuan.com/course/2669_2.html
反转二叉树:http://www.jikexueyuan.com/course/2714_4.html