阿里淘宝部门一面,已通过!

8,644 阅读9分钟

大家好,我是程序员小灰。

在今年,小灰的一位读者在秋招提前批的时候,面试了阿里巴巴杭州base的淘宝部门,已顺利拿到offer。

这位读者为了能帮助到更多程序员朋友,把阿里第一轮面试的过程详详细细做了记录和总结,希望大家能够从中获得启发。

面试者背景介绍

先大概说一下我的背景吧,本科211自动化专业,硕士Top2学校非科班,字节,京东两端大厂实习,一段侧重推荐算法开发,另一段Java后端开发,各4个月的实习经历。

在今年24届秋招提前批,投递了阿里巴巴杭州base的淘宝部门,目前已oc拿到offer,全程面试内容主要包括三个部分:实习项目,项目经验,手撕代码,八股文理论基础考察。

以下为淘宝一面的内容,面试考察非常全面,整个面试的时长1小时零5分钟,选取了其中比较关键的干货内容与大家分享,包含了作者的面试后总结与反思。

一面面试过程

1. 面试官:同学你好,因为我们是第一轮技术面试,第一轮面试,我们会以Java的八股文基础以及算法题的考察为主。同学,现在可以开始了吧?同学你先做一个简单的自我介绍吧!

我:好的,面试官,我这边没有问题。自我介绍...

小结:其实虽然说是以八股文和算法题的考察为主,但是现在觉得自我介绍时,应该可以“引导”面试官多聊一聊项目,毕竟更加擅长。

2. 面试官:我看你本科是自动化专业的,研究生期间转到了软件工程。那你的计算机基础怎么样?我问你几个关于数据结构的问题,你能给我讲一下二叉树的遍历方法与具体原理吗?

我:二叉树的遍历方法包括前序,中序,后序和层次遍历,其中二叉树的前序遍历是先去访问二叉树的根节点,然后遍历左子树,右子树节点。

中序遍历是按照左子树,根节点,右子树顺序,后序遍历是按照左子树,右子树,根节点进行二叉树的遍历。

而层序遍历则是借助Queue队列进行按照二叉树的层次进行上下顺序的打印。

小结:几种遍历方法,感觉说完,就会有算法题要写了,果然...

面试官:好的,既然你已经提到了二叉树的数据结构,也说了几种遍历形式,那我现在想让你写一道算法题。

你刚才说的中序遍历你用代码实现一下,并且我希望你能使用迭代以及递归两种形式进行实现的。

我:

import java.util.Stack;
public class Main {
    public static class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;
        TreeNode(int val) {
            this.val = val;
        }
    }
    public static void main(String[] args) {
        // 构建二叉树
        TreeNode root = new TreeNode(1);
        TreeNode left = new TreeNode(2);
        TreeNode right = new TreeNode(3);
        TreeNode leftOfLeft = new TreeNode(4);
        TreeNode rightOfLeft = new TreeNode(5);
        TreeNode leftOfRight = new TreeNode(6);
        TreeNode rightOfRight = new TreeNode(7);
        root.left = left;
        root.right = right;
        left.left = leftOfLeft;
        left.right = rightOfLeft;
        right.left = leftOfRight;
        right.right = rightOfRight;
        // 执行中序遍历
        System.out.print("Inorder Traversal (Recursive): ");
        inorderTraversalRecursive(root);
        System.out.println();
        System.out.print("Inorder Traversal (Iterative): ");
        inorderTraversalIterative(root);
    }
    // 中序遍历递归实现
    public static void inorderTraversalRecursive(TreeNode root) {
        if (root == null) {
            return;
        }
        inorderTraversalRecursive(root.left);
        System.out.print(root.val + " ");
        inorderTraversalRecursive(root.right);
    }
    // 中序遍历迭代实现
    public static void inorderTraversalIterative(TreeNode root) {
        if (root == null) {
            return;
        }
        Stack<TreeNode> stack = new Stack<>();
        TreeNode current = root;
        while (current != null || !stack.isEmpty()) {
            while (current != null) {
                stack.push(current);
                current = current.left;
            }
            current = stack.pop();
            System.out.print(current.val + " ");
            current = current.right;
        }
    }
}

小结:面试时的手撕代码,和刷leetcode时的感觉还是不太一样的,类似TreeNode二叉树节点类,也需要自己进行手动定义。同时需要自己构建测试用例,还是有一定难度的。

3. 面试官:我们再聊聊计算机网络的基础,TCP和UDP两种网络通信协议的区别,你说一下吧?

我:TCP和UDP两种通信协议区别在于TCP是面向连接的,传输具有可靠性,而UDP不保证数据可靠性的,TCP的建立连接需要三次握手和四次挥手,而UDP不需要,同时TCP通信具有流量控制和拥塞控制机制,UDP通信协议则没有;TCP传输可以保证数据的传输顺序,而UDP传输不一定能保证数据传输顺序。

4. 面试官:同学我看简历上你说你了解JAVA的垃圾回收机制。曾在一家实习中涉及了JVM调优,你能简单说一下,你是怎么对JVM内存进行调优的?

我:JVM的垃圾回收算包括标记-清除方法 复制方法 标记-整理方法 三种垃圾回收算法。

标记-清除方法会扫描堆中的对象,删除未标记的对象,使其内存可供再次使用。但是清除阶段会导致内存碎片,需要额外的工作来合并碎片。

复制方法是将堆内存分为两个区域:From区和To区。在垃圾收集时,从From区中将存活的对象复制到To区。清空From区,将From区和To区的角色互换,以便下一次垃圾收集,但是浪费了一半的内存空间。

标记-整理方法类似于标记-清除,但在标记阶段后,会将存活对象向一端移动,从而压缩内存,可以减少内存碎片

小结:这两个问题就是比较正常的八股文了,但是都联系了部分实习经历中的项目,所以八股文不能只死记硬背,需要理解其原理。

5. 面试官:阿里这边的技术栈,数据库使用的MySQL,如果现在MySQL的查询速度变慢的时候,你有什么优化办法吗?

我:首先使用Explain进行慢查询日志的执行计划解析,然后对查询的限定条件的数据库字段增加索引机制,也可以借用Redis缓存数据库的机制,进行缓存的查询加速。

小结:属于实际的场景题目,回答面试官觉得很满意,当然也可以采用分库分表的机制,但是相对说,工作量会比较大。

6. 面试官:我现在给你一条写好的SQL语句,你来判断它是否使用应用到了你加的索引呢?

发了一条SQL,判断是否能用到索引(select * from table where name like "%林")

我:这个SQL查询中的name字段使用like模糊查询符,但是模糊搜索字符串的模式是以通配符%开头的,即"%林"。这种情况下,通常无法充分利用索引。

7. 面试官:你刚才提到了Redis缓存数据库,那你有用过Redis操作命令吗?Redis数据库怎么查出所有Keys列表,并且扫描大key呢?

我:使用SCAN 0 命令在Redis数据库的终端执行,可以扫描Redis数据库中的键值对列表。扫描大Key这个没尝试过,但是一般来说,就是把List集合数据格式的key进行重点筛选。

小结:后续在面完后,查询了一下,可以使用Redis RDB Tools工具进行大Keys的扫描。

8. 面试官:说对了一部分,你可以下去再了解一下,为什么Redis它明明是单线程的,它的查询速度会这么快?

我:经典八股文,虽然Redis是单线程的,但它使用非阻塞I/O来处理多个客户端的请求。这意味着当一个客户端的请求需要等待外部I/O,同时Redis是基于内存机制读写,相比于MySQL的硬盘读写机制,速度更快!

9. 面试官:同学,我这边想问的技术内容就差不多了,最后我们再做一道简单的算法题,做完了讲一下你的思路,同时你有什么问题想问我的吗?

我:所有手撕算法需要使用IDEA,共享屏幕完成,并且面试官还会和你交流思路。

返回链表倒数第K个节点:

public class Main {
    static class ListNode {
        int val;
        ListNode next;
        ListNode(int val) {
            this.val = val;
        }
    }

    public static ListNode findKthFromEnd(ListNode head, int k) {
        if (head == null || k <= 0) {
            return null;
        }
        ListNode slow = head;
        ListNode fast = head;
        // 将快指针先移动k步
        for (int i = 0; i < k; i++) {
            if (fast == null) {
                return null; // 处理k大于链表长度的情况
            }
            fast = fast.next;
        }
        // 同时移动快慢指针,直到快指针到达链表末尾
        while (fast != null) {
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
    }

    public static void main(String[] args) {
        ListNode node = new ListNode(0);
        node.next = new ListNode(1);
        node.next.next = new ListNode(2);
        node.next.next.next = new ListNode(3);
        int k = 2;
        ListNode K_node = findKthFromEnd(node,k);
        System.out.println(K_node.val);
    }
}

思路:这道算法题使用快慢指针进行解答,新建两个起始指针,快指针先走K步,然后快慢指针同时运行,当快指针先运行到链表的尾结点,恰好此时慢节点的指向位置就是倒数第K个节点,返回即可。

提问:我想问一下您,咱们部门是做什么业务的?使用什么技术栈?

10. 面试官:我们这边主要是做辅助天猫数据中间数据存储的,你可以理解为辅助双十一的流量压力分流,使用的技术栈,我看和你挺匹配的,基本使用的都是MySQL数据库,以及kafka消息中间件。

我:好的,感谢面试官,我没有其他的问题了,拜拜~

小结:一般来说,如果面试官很愿意和你讲解公司的业务方向,面试的通过概率就非常大了,因为如果没有通过,没有必要和你浪费时间,同时你也可以表现的你和工作业务很匹配,增加一点印象分。

面试总结反思

一面总结:不同面试官的面试风格,可能真的不一样,我也遇到过第一轮面试就细聊项目经验的,但是阿里淘宝的这轮面试,感觉比较侧重Java的八股文以及算法题。

从一上来的二叉树的中序遍历算法题,以及最后一道算法题,甚至中间的SQL语句,整体面试风格比较务实。同时感觉面试的内容很灵活,对知识的掌握要求能灵活运用。整体感觉难度中等。

面试结果:顺利通过,已约二面