记阿里的第二次面试

                                 记阿里的第二次面试

      我记得是貌似是星期二晚上,刚好我晚上还有节项目组织管理的课,正上第一节课时阿里那边就打电话过来了,我就直接从教室里出去在楼梯窗口那里接电话。听到面试官第一句话时我就知道这次的面试官肯定大小是个官。

       首先还是自我介绍,嗯,基本还是把上次的自我介绍说了一遍,然后流程和上一次电话面试差不多,也是问一下项目中用了哪些技术,问对spring boot有没有了解,虽然用过几次spring boot,但阿里这种面试,真的不敢说自己了解spring boot,怕给自己挖坑,问起来基本答不上来让面试官觉得你这人就这点水平,就这种程度就敢说自己了解。

      然后又问了一些关于Java线程、线程同步的问题,同步用sychronized关键词作用于实例方法和作用于静态方法中的区别,这点我还是比较熟悉的,作用于实例方法中就是把this对象当对锁对象嘛,作用于静态方法就是把类对象当作锁对象,然后问了我一些基本的集合框架,就简单地说了下Set接口、List接口、Queue、Stack、Map,HashMap是线程不安全的,HashTable是线程安全的,但HashTable把整个数据结构用一个锁锁住了,并发时效率不高,而ConcurrentHashMap是线程安全的,而且是采用了多段锁机制,数据结构每一段用一个锁来锁住,当多个线程访问同一段时,就要等待,而访问不同段时,由于是不同的锁对象,所以可以并发。然后还问了Java一些其他的东西,反正感觉Java基础的东西我还是没问题的。

       好吧,其实第一次面试我真的以为我已经凉了,所以数据库还是没怎么复习,面试官又开始问数据库的东西,真的很忧伤。这次开始问的还是比较具体的,开始就问怎样增删改查,我直接就答insert into ...、delete ...、update ...和select ... from句子,然后问我如何分组,当然就是group by了嘛,问分组条件,这个问题我开始没明白,我以为是问我where,他纠正我是用having,好吧,其实我是知道having的,我以为他是问我基本的条件查询,没问我连接的问,连接其实我也还记得一些,有内连接和外连接,内连接是两个表满足所有连接条件的行的笛卡尔各,而外连接分为左外连接、右外连接和全外连接,左外连接就是连接后左表的行都返回,而右表只返回和左表满足条件的行,右外连接则相反,全外连接则返回所有的连接行,即满足连接条件的笛卡尔积,内连接和外连接的区别就是内连接只会返回满足条件的行,左右表一定都会返回,而外连接则会返回一些左表或右表不满足条件的行,连接条件用on关键词,on后接一个bool表达式,跟接在wher后的一样。然后问我数据库的乐观锁与悲观锁,这下我就悲剧了,我记得数据库上老师确实讲过锁的,但是我给忘了,90多分考过数据库,现在居然忘成了这样,真的感觉可悲。后来上网查了下,悲观锁其实就是根据数据库提供的锁,当要对一个记录做操作时,就要先尝试对这个记录加上排他锁,也就是x锁,如果加锁失败,就说明这个记录正在被修改,就会抛出异常或者等待,具体要怎样就会根据程序中的业务逻辑了,如果加锁成功,就可以对这个记录做相应操作,事务完成后再解锁。如果在加锁而未解锁期间再对这个记录加排他锁,就会等待或者抛出异常。这和我们普通的事务管理差不多。在mysql中使用悲观锁时,直接把自动提交改成0就可以了,这样就需要用sql命令来手动提交事务。而乐观锁就比较松了,乐观锁很“乐观”,认为两个事务如果不会相互影响,就可以并发地进行事务,乐观锁认为其他事务都是友好的,不会修改自己的记录,乐观锁不会给记录加上锁,而是给记录添加上一个版本号,每次修改一条数据时都要把先前查到的版本号+1,在提交修改前,如果发现当前版本是这个记录的最新版本,就执行更新,如果不是就要回滚或者抛出异常,很明显,这样的操作使用于那些读多写少的场景,因为读多时如果每次都加锁,效率会非常低,读不会修改记录,因为不加锁会大大提高效率。

       最后他跟我说他是阿里的数据技术与产品部门的,主要是建立大并发和大数据的解决方案,给我提了一些建立,让我不要紧张,自我介绍时要更有条理一些,还要多了解一些当前流行的技术,比如说区块链技术、微服务以及大数据云计算的东西,说在他们部门有很多大佬,研究领域很广泛,如果我进入他们部门,会有专门的人才培养计划,会根据我的爱好的能力进行相关的培养。嗯,不愧是中国乃至全世界数一数二的互联网企业,对于员工,第一个想到的不是马上做企业做多少事,而是培养人才,可能这就是大厂的人才精神吧。最后问我还有没有什么想问的,我由于是从课上跑出去的,想快点回去上课了,就说现在还没有其他想问的。然后就挂电话了,过了一会又打电话过来说晚上会发一个编程测试题给我,让我当晚做完回复给他。题目其实挺简单的,嗯,还是贴出来吧

//评测题目: 给定一集合Set<Node> nodes, 
//其中Node类中id和parentId用于表示其与其他Node对象的父子关系 
//parentId为0的是root节点,
//要求,提供一个方法,将上述集合作为入参,返回值为json字符串,格式为树状
//{id:1,parentId:0,code:"node1",children:[{id:2,parentId:1,code:"node2",children:[...]},{...}]}
//没有任何限制,可以使用开源框架实现
public class Node{
  private int id;
  private int parentId;
  private String code;
}

我的解决方法如下:

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/**
 *
 * @author Benson
 * @date 2018年3月5日 下午7:20:50
 * @emial [email protected]
 * @description 编程测试
 * 				//评测题目: 给定一集合Set<Node> nodes,
 *              //其中Node类中id和parentId用于表示其与其他Node对象的父子关系
 *              //parentId为0的是root节点,
 *              //要求,提供一个方法,将上述集合作为入参,返回值为json字符串,格式为树状
 *              //{id:1,parentId:0,code:"node1",children:[{id:2,parentId:1,code:"node2",children:[...]},{...}]}
 *              //没有任何限制,可以使用开源框架实现
 *              public class Node{
 *              	private int id;
 *                  private int parentId;
 *                  private String code;
 *                	}
 */
public class Node {
	private int id;
	private int parentId;
	private String code;

	/**
	 *
	 * @author Benson
	 * @date 2018年3月5日 下午7:21:34
	 * @emial [email protected]
	 * @description 用MyNode把Node封装成树的节点
	 */
	public static class MyNode {
		private Node node;
		private List<MyNode> children = new LinkedList();
	}

	/**
	 * 类似先序遍历
	 *
	 * @param root
	 * @param sb
	 */
	public static void preTra(MyNode root, StringBuilder sb) {
		sb.append("{id:").append(root.node.id).append(",").append("parentId:").append(root.node.parentId).append(",")
				.append("code:\"").append(root.node.code).append("\",").append("children:[");
		for (MyNode child : root.children) {
			preTra(child, sb);
			sb.append(",");
		}
		if (root.children.size() > 0) {
			sb.deleteCharAt(sb.length() - 1);
		}
		sb.append("]}");
	}

	/**
	 * 把节点集合转换成树形的json字符串
	 *
	 * @param nodes
	 * @return
	 */
	public static String set2JSON(Set<Node> nodes) {
		Map<Integer, MyNode> map = new HashMap();
		Iterator<Node> iterator = nodes.iterator();
		while (iterator.hasNext()) {
			MyNode myNode = new MyNode();
			Node node = iterator.next();
			myNode.node = node;
			map.put(node.id, myNode);
		}

		for (Entry<Integer, MyNode> entry : map.entrySet()) {
			if (entry.getValue() == map.get(0)) {
				continue;
			}
			MyNode pNode = map.get(entry.getValue().node.parentId);
			if (pNode == null) {// 除了root外还有节点没有父节点,不能生成树形结构
				throw new IllegalArgumentException("node that id=" + entry.getKey() + " dose not have parent root");
			}
			pNode.children.add(entry.getValue());
		}

		StringBuilder sb = new StringBuilder();
		preTra(map.get(0), sb);
		return sb.toString();
	}

	/**
	 * 测试
	 *
	 * @param args
	 */
	public static void main(String[] args) {
		Set<Node> nodes = new HashSet();
		Node node0 = new Node();
		node0.code = "node0";
		node0.id = 0;
		node0.parentId = -1;
		Node node1 = new Node();
		node1.code = "node1";
		node1.id = 1;
		node1.parentId = 0;
		Node node2 = new Node();
		node2.code = "node2";
		node2.id = 2;
		node2.parentId = 0;
		Node node3 = new Node();
		node3.code = "node3";
		node3.id = 3;
		node3.parentId = 1;
		Node node4 = new Node();
		node4.code = "node4";
		node4.id = 4;
		node4.parentId = 1;
		Node node5 = new Node();
		node5.code = "node5";
		node5.id = 5;
		node5.parentId = 2;
		Node node6 = new Node();
		node6.code = "node6";
		node6.id = 6;
		node6.parentId = 2;

		Node node7 = new Node();
		node7.code = "node7";
		node7.id = 7;
		node7.parentId = 4;

		nodes.add(node0);
		nodes.add(node1);
		nodes.add(node2);
		nodes.add(node3);
		nodes.add(node4);
		nodes.add(node5);
		nodes.add(node6);
		nodes.add(node7);
		System.out.println(set2JSON(nodes));
	}
}

基本思想就是把节点封装一下,形成一个树结构,用hash表还暂存一下,避免重复遍历,因为hash表在理想状态下的查询时间复杂度为O(1)嘛,这样就把复杂遍历的O(n^2)变成了O(n)了,整个算法的时间复杂度也就变成了O(n)了,想了一下,由于无论如何都是需要遍历一次Set集合的,因为这个题目最好的复杂度也是O(n)了,于是就把这个答案提交上去了,也不知道他对我的答案满不满意,反正算我通过了,应聘状态变成面试中了。如果有现好的算法的博友,欢迎发邮件我([email protected])交流交流。

       总体感觉还是挺好的,虽然还是一顿虐,但确实让我感受到了大厂的人才培养精神,对阿里的好印象再次提升,希望后面的面试能够继续顺利吧。

猜你喜欢

转载自blog.csdn.net/qq_31728311/article/details/79482635
今日推荐