面经(1)

八股分为:基础知识,底层原理,场景应用

  • 基础知识:javaguide, 死记硬背,思维导图
  • 底层原理:八股合集,面经+GPT+整理
  • 场景应用:面经+积累

20240611

面向面经背八股,小米面经

小米一面面经

自我介绍(项目经历和实习经历)

在自我介绍时,可以简要介绍自己的教育背景、工作经历、主要技能和项目经历。着重突出在项目中的具体职责和贡献,以及所使用的技术和取得的成果。

1. Java的基本数据类型

Java有8种基本数据类型:

  • byte: 8位,范围是 -128 到 127
  • short: 16位,范围是 -32,768 到 32,767
  • int: 32位,范围是 -2^31 到 2^31-1
  • long: 64位,范围是 -2^63 到 2^63-1
  • float: 32位,单精度浮点数
  • double: 64位,双精度浮点数
  • char: 16位,无符号 Unicode 字符
  • boolean: 只有两个值:truefalse

2. 了解哪些基本的数据结构

常见的数据结构包括:

  • 数组
  • 链表(单链表、双链表)
  • 队列(普通队列、优先队列、循环队列)
  • 哈希表
  • 树(如二叉树、红黑树、B树、B+树)
  • 图(有向图、无向图)
  • 堆(如二叉堆、斐波那契堆)

3. 简单介绍二叉树

二叉树是一种树形数据结构,其中每个节点最多有两个子节点,分别称为左子节点和右子节点。常见的二叉树类型有:

  • 完全二叉树:除了最后一层,所有层的节点都填满,最后一层的节点都靠左对齐。
  • 满二叉树:每个节点要么是叶子节点,要么有两个子节点。
  • 二叉搜索树:对于每个节点,其左子节点的值小于该节点的值,其右子节点的值大于该节点的值。

4. 知道MySQL吗?MySQL中跟二叉树相关的结构你知道吗?

在MySQL中,索引结构与二叉树相关的是B树和B+树。B树是一种自平衡的多路搜索树,B+树是B树的一种改进版,所有的叶子节点形成一个有序链表。MySQL的InnoDB存储引擎使用B+树来实现索引。

5. 展开说说B树和B+树

  • B树:一种自平衡的多路搜索树,节点可以有多个子节点。所有叶子节点的深度相同,节点中的元素按顺序排列。
  • B+树:B树的改进版,非叶子节点不存储数据,只存储索引,所有数据都存储在叶子节点中。叶子节点之间形成一个有序链表,方便范围查询。

6. MySQL中现在主要用B树还是B+树?B+树的优势?

MySQL中的InnoDB存储引擎主要使用B+树。B+树的优势包括:

  • 所有数据都在叶子节点,查询效率高
  • 叶子节点形成有序链表,方便范围查询
  • 非叶子节点只存储索引,减少了树的高度,提高了查询效率

7. Redis的基本类型

Redis支持以下基本数据类型:

  • 字符串(String)
  • 列表(List)
  • 集合(Set)
  • 有序集合(Sorted Set)
  • 哈希(Hash)

8. Redis中Set和Sorted Set的区别

  • Set:无序集合,不允许重复元素,操作时间复杂度为O(1)。
  • Sorted Set:有序集合,每个元素都会关联一个分数,Redis通过分数进行排序,操作时间复杂度为O(log N)。

9. 有了解过JVM方面的知识吗?垃圾回收

JVM(Java虚拟机)是Java程序运行的基础,负责内存管理和垃圾回收。垃圾回收机制(GC)主要有以下几种算法:

  • 标记-清除(Mark-Sweep)
  • 标记-整理(Mark-Compact)
  • 复制(Copying)
  • 分代收集(Generational Collecting):年轻代(Young Generation)和老年代(Old Generation)分别采用不同的GC算法。

10. TCP通过什么来保证可靠传输的?

TCP通过以下机制保证可靠传输:

  • 三次握手建立连接
  • 序列号和确认号
  • 滑动窗口
  • 超时重传
  • 流量控制
  • 拥塞控制

11. 细说三次握手、四次挥手

三次握手:

  1. 客户端发送SYN包(同步序列编号)请求建立连接。
  2. 服务器接收到SYN包,返回一个SYN+ACK包表示同意建立连接。
  3. 客户端收到SYN+ACK包,回复一个ACK包,连接建立成功。

四次挥手:

  1. 客户端发送FIN包(结束连接)请求断开连接。
  2. 服务器接收到FIN包,返回一个ACK包,表示确认断开连接请求。
  3. 服务器发送FIN包请求断开连接。
  4. 客户端收到FIN包,返回一个ACK包,连接断开。

「手撕」

链表相关

将链表转成数字,相加之后再转成链表。示例:

  • 输入:链表一:1->6->3,链表二:7->1->2
  • 相当于361 + 217 = 578
  • 输出:8->7->5
class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}

public class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode dummyHead = new ListNode(0);
        ListNode p = l1, q = l2, curr = dummyHead;
        int carry = 0;
        while (p != null || q != null) {
            int x = (p != null) ? p.val : 0;
            int y = (q != null) ? q.val : 0;
            int sum = carry + x + y;
            carry = sum / 10;
            curr.next = new ListNode(sum % 10);
            curr = curr.next;
            if (p != null) p = p.next;
            if (q != null) q = q.next;
        }
        if (carry > 0) {
            curr.next = new ListNode(carry);
        }
        return dummyHead.next;
    }
}

「继续QA」

1. 手撕这个算法的时间复杂度

上述算法的时间复杂度是O(max(m, n)),其中m和n分别是两个链表的长度。因为需要遍历两个链表的每一个节点。

2. 如果能实习,每周几天、实习周期?

根据个人情况回答,可以说出每周可以实习的天数和希望的实习周期长度。例如:

  • 每周3-5天
  • 实习周期为3-6个月

参考资料

  • 牛客网:https://www.nowcoder.com/feed/main/detail/61f2b3801d6b42d4b39adcf461b784b5?sourceSSR=users

小米二面面经

#面经

「QA」

  1. MyBatis 具体是干什么用的?在使用它之前可能会遇到什么问题,使用它之后会给你的项目带来什么便利?
  2. 项目中有没有用到线程池?
  3. MyBatis 中涉及到动态 sql,sql 的标签能说几个吗
  4. MyBatis 能执行一对一或者一对多关联的查询吗?有哪些实现方式?
  5. SpringBoot 中,读取配置的时候有哪些方式?
  6. Integer 对象和基本数据类型 int,哪个占用更多的内存
  7. ArrayList 和 LinkedList 的区别
  8. 对象的浅拷贝和深拷贝
  9. 了解哪些设计模式?
  10. (逐渐离谱了起来):tensorflow 是用来干嘛的
  11. 解释一下 softmax
  12. (聊我的科研项目里) 常用的强化学习算法 为什么用 PPO 算法不用 DQN 算法?
  13. 为什么不用 A3C 算法?
  14. 讲讲 Transformer……

「手撕」

  1. 很简单的数组题 2min 做完
  2. 反转链表 II 力扣 92 题(写过但忘了 啊啊啊啊啊啊)

好的,以下是对这些面试问题的详细回答:

1. MyBatis 具体是干什么用的?在使用它之前可能会遇到什么问题,使用它之后会给你的项目带来什么便利?

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。使用前可能遇到的问题包括:

  • 学习曲线:需要花时间学习和理解 MyBatis 的配置和使用方式。
  • 配置复杂性:需要配置 XML 文件或注解,初期配置较复杂。 使用之后的便利包括:
  • 降低了直接使用 JDBC 的复杂性,提高开发效率。
  • 支持动态 SQL,灵活性高。
  • 支持高级映射,可以方便地将查询结果映射为 Java 对象。

2. 项目中有没有用到线程池?

线程池用于管理和复用多个线程,避免频繁创建和销毁线程带来的开销,提高系统性能。常用的线程池有:

  • Executors.newFixedThreadPool(int n): 固定大小的线程池。
  • Executors.newCachedThreadPool(): 可缓存的线程池。
  • Executors.newScheduledThreadPool(int n): 支持定时和周期性任务的线程池。
  • Executors.newSingleThreadExecutor(): 单线程池。

3. MyBatis 中涉及到动态 sql,sql 的标签能说几个吗

MyBatis 中的动态 SQL 标签包括:

  • <if>: 根据条件是否包含某段 SQL。
  • <choose>: 类似 switch 语句,包含 <when><otherwise>
  • <where>: 自动处理 AND/OR 逻辑。
  • <set>: 用于动态更新语句。
  • <foreach>: 用于遍历集合生成动态 SQL。
  • <trim>: 自定义 SQL 片段。

4. MyBatis 能执行一对一或者一对多关联的查询吗?有哪些实现方式?

MyBatis 可以执行一对一或一对多的关联查询。实现方式包括:

  • 使用 resultMap 进行结果映射,定义关联关系。
  • 在 SQL 中使用 JOIN 语句进行关联查询。
  • 使用 associationcollection 标签实现一对一和一对多映射。

5. SpringBoot 中,读取配置的时候有哪些方式?

SpringBoot 读取配置的方式包括:

  • @Value: 注入单个配置属性。
  • @ConfigurationProperties: 批量注入配置属性。
  • Environment 对象:通过 environment.getProperty 方法获取配置。
  • @PropertySource: 加载自定义配置文件。
  • application.propertiesapplication.yml: 默认配置文件。

6. Integer 对象和基本数据类型 int,哪个占用更多的内存

Integer 对象占用的内存更多。int 是基本数据类型,直接存储数值,占用 4 个字节。而 Integer 是包装类,除了存储数值外,还包含对象头信息,至少占用 16 个字节(具体根据 JVM 实现和对象头信息有所不同)。

7. ArrayList 和 LinkedList 的区别

  • ArrayList: 基于动态数组实现,查询速度快(O(1)),增删速度慢(O(n))。
  • LinkedList: 基于双向链表实现,查询速度慢(O(n)),增删速度快(O(1))。

8. 对象的浅拷贝和深拷贝

  • 浅拷贝: 只复制对象的基本类型和引用类型的地址,不复制引用对象本身。修改引用对象会影响原对象。
  • 深拷贝: 复制对象的基本类型和引用对象,生成一个全新的对象,互不影响。

9. 了解哪些设计模式?

常见的设计模式包括:

  • 创建型模式: 工厂模式、抽象工厂模式、单例模式、建造者模式、原型模式。
  • 结构型模式: 适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
  • 行为型模式: 策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、解释器模式、中介者模式。

10. TensorFlow 是用来干嘛的

TensorFlow 是一个开源的机器学习框架,主要用于深度学习模型的开发、训练和部署。它提供了灵活的计算图结构,可以在 CPU、GPU 和 TPU 上运行,支持分布式计算。

11. 解释一下 softmax

Softmax 是一种激活函数,常用于多分类模型的输出层。它将输入的 logits 转换为概率分布,公式如下: [ \text{softmax}(x_i) = \frac{e^{x_i}}{\sum_{j} e^{x_j}} ] 其中,( x_i ) 是输入向量的第 i 个分量,输出的每个分量都是介于 0 和 1 之间的概率值,且所有分量的和为 1。

12. 常用的强化学习算法 为什么用 PPO 算法不用 DQN 算法?

PPO(Proximal Policy Optimization)和 DQN(Deep Q-Network)都是常用的强化学习算法。选择 PPO 而不是 DQN 的原因包括:

  • PPO 是基于策略梯度的算法,适用于连续动作空间,而 DQN 主要用于离散动作空间。
  • PPO 引入了剪切概率比(clipped probability ratio),在更新策略时保持平稳,训练更稳定。
  • PPO 更加简单高效,不需要像 DQN 那样复杂的经验回放和目标网络。

13. 为什么不用 A3C 算法?

尽管 A3C(Asynchronous Advantage Actor-Critic)是一个有效的算法,但相较于 PPO,有以下缺点:

  • A3C 使用多线程并行,容易受到线程调度和同步的影响。
  • PPO 不需要复杂的多线程设置,具有更高的样本效率和训练稳定性。
  • PPO 算法相对更简单,更容易调试和实现。

14. 讲讲 Transformer

Transformer 是一种用于自然语言处理的神经网络模型,克服了传统 RNN 模型在处理长序列时的局限性。它主要由以下部分组成:

  • 编码器(Encoder): 由多个相同的编码层堆叠而成,每层包含自注意力机制和前馈神经网络。
  • 解码器(Decoder): 结构类似于编码器,但每个解码层在自注意力机制之后还增加了一个对编码器输出的注意力机制。
  • 自注意力机制(Self-Attention): 计算输入序列中每个元素与其他元素的关系,以捕捉全局依赖关系。
  • 位置编码(Positional Encoding): 为了保留序列信息,向输入中添加位置信息。 Transformer 的优势包括:
  • 并行化计算效率高,适合处理长序列。
  • 能够捕捉序列中全局依赖关系。

「手撕」

1. 很简单的数组题 2min 做完

假设这是一个简单的求数组最大值的题目,代码如下:

public int findMax(int[] nums) {
    int max = nums[0];
    for (int num : nums) {
        if (num > max) {
            max = num;
        }
    }
    return max;
}

2. 反转链表 II 力扣 92 题

反转链表 II 的解题思路是找到要反转的起点和终点,进行局部反转。代码如下:

public ListNode reverseBetween(ListNode head, int m, int n) {
    if (head == null) return null;
    ListNode dummy = new ListNode(0);
    dummy.next = head;
    ListNode pre = dummy;
    for (int i = 0; i < m - 1; i++) pre = pre.next;
    ListNode start = pre.next;
    ListNode then = start.next;
    for (int i = 0; i < n - m; i++) {
        start.next = then.next;
        then.next = pre.next;
        pre.next = then;
        then = start.next;
    }
    return dummy.next;
}
/**
 * Definition for singly-linked list.
 * public class ListNode {
 * int val;
 * ListNode next;
 * ListNode() {}
 * ListNode(int val) { this.val = val; }
 * ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseBetween(ListNode head, int m, int n) {
        if (head == null)
            return null;
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode pre = dummy;

        for (int i = 0; i < m - 1; i++)
            pre = pre.next;

        ListNode start = pre.next;

        ListNode cur = null;
        ListNode newEnd = start;
        for (int i = 0; i <= n - m; i++) {
            ListNode nxt = start.next;
            start.next = cur;
            cur = start;
            start = nxt;
        }
        pre.next = cur;
        newEnd.next = start;

        return dummy.next;
    }
}

希望这些回答能帮助你更好地准备面试。祝你面试成功!