0%

众安保险20250327笔试

单选25题,编程2题,开一个摄像头,手机监控。

单选题

  1. 后缀表达式求最大值
    7 3 8 2 3 x - 6 5 - 符号 符号 +
    两个符号处填什么符号,求表达式最大可能的值
  2. Java集合
    isEmpty()size==0等价吗
    Array.asList() 传入数组int[]作为参数,调用get方法,会有indexoutofbound错误吗
    foreach 中可以使用 remove/add方法吗
    toMap的value可以为null吗
  3. 设计模式,哪种设计模式是数据驱动的
    策略模式,根据数据选择不同的策略
  4. 递归算法的时间复杂度
    f() {
    for()
    for()
    f(l, mid)
    f(mid + 1, r)
    }
  5. 操作系统:5GB磁盘,簇大小为2kb,用位图法管理空闲空间,存放位图的簇需要多个簇
    1. 计算磁盘的总簇数
      磁盘总大小 = 5 GB = 5 × 1024 × 1024 KB = 5,242,880 KB
      簇大小 = 2 KB
      总簇数 = 磁盘总大小 / 簇大小 = 5,242,880 KB / 2 KB = 2,621,440 个簇
    2. 计算位图的大小
      位图法使用 1 bit 表示 1 个簇 的状态(0 = 空闲,1 = 已占用)。
      位图需要的总 bit 数 = 总簇数 = 2,621,440 bits
      转换为字节(Byte):
      1 Byte = 8 bits
      位图大小(Bytes)= 2,621,440 bits / 8 = 327,680 Bytes
    3. 计算位图占用的簇数
      簇大小 = 2 KB = 2 × 1024 Bytes = 2048 Bytes
      位图占用的簇数 = 位图大小 / 簇大小 = 327,680 Bytes / 2048 Bytes ≈ 160 个簇
  6. 哪个不是Java的标识符(变量名、方法名、类名) a3x default string $123
    default是关键字,不能作为标识符
  7. java类加载机制,选项和父类加载器有关,采用继承方式复用父类加载器吗(错误)
    双亲委派模型(Parent Delegation Model)
    • Java 类加载器采用 组合(Composition) 而非 继承(Inheritance) 的方式复用父类加载器。
    • 每个类加载器(除 Bootstrap 外)都有一个 父类加载器(Parent ClassLoader),但这是通过 内部引用 实现的,而不是继承关系。
    • 类加载时,子加载器会先委托父加载器加载,父加载器无法完成时才会自己加载。
  8. 链栈Stack,栈顶指针为P,节点S,
    S->next=P P=S 是什么操作,是链栈的入栈(Push)操作
  9. 基数排序
    基数排序是一种 非比较型整数排序算法,其核心思想是 按位分配和收集,从最低位(LSD,Least Significant Digit)或最高位(MSD)开始逐位排序。
    按最低位(个位)排序:
    • 将所有数字根据个位数字分配到 0~9 的桶中。
    • 按桶顺序(0→9)依次收集,形成第一次排序结果。
  10. SQL 隔离级别 InnoDB 默认是可重复读
  11. 批处理操作系统的特点
    成批处理、脱机、多道
    不是特点:多路属于分时系统的核心特点
  12. 电报交换、报文交换、分组交换时延排序
    电报交换 > 报文交换 > 分组交换
    • 报文交换介于两者之间,但因效率低下已被分组交换取代。
    • 最低时延:分组交换(现代网络首选)。
    • 最高时延:电报交换(因连接建立和独占性)。
  13. Java I/O 流用哪种设计模式
    主要采用了 装饰器模式(Decorator Pattern),同时结合了 适配器模式(Adapter Pattern) 和 工厂模式(Factory Pattern) 的部分思想。
    装饰器模式:在不修改原有类的基础上,通过嵌套包装(装饰)来添加新功能。
  14. P/V 信号量实现互斥初始值设置为1
  15. Redis 端口号、默认数据库、数据库默认数量、daemonize是守护进程吗
    端口号6379。默认数据库是0 数据库默认数量是16。daemonize是守护进程
  16. 完全二叉树 第五层6个节点,根节点是第一层,叶子结点数最少多少个
  17. 递归求最大公约数(线段树思想),填代码
  18. 分组交换
    分组交换三种方式:数据报、存储转发、虚电路
    数据报可能出现失序、丢失、重复
    存储转发 限制发送数据大小,分组不能超过最大传输单元
    虚电路 通信前建立逻辑路径(虚电路),传输后释放。
  19. SpringBoot 两个类区别
    @Import 修饰类,通常和 @Configuration 一起使用
    @ImportResource 修饰类,加载方式是xml文件
  20. 求子串个数
  21. Linux 看文件节点信息的命令 ls -i
  22. Zookeeper 什么情况下会重新选举 leader
    当 Leader 出现故障或集群状态变化时,会触发 Leader 重新选举
  23. Mysql 求select结果
    select count(*) from t where not exist (select * from t where id >= 1002)
    • 如果 **表 t 中至少有一行 id >= 1002**,则 EXISTS 返回 TRUENOT EXISTS 返回 FALSE,最终 COUNT(*) 结果为 0
    • 如果 **表 t 中没有任何行 id >= 1002**,则 NOT EXISTS 返回 TRUE,最终 COUNT(*) 结果为 t 的总行数
  24. 🌟(别的笔试题里做过一次)sleep() 和 wait() 区别
    sleep() 不释放锁
    • 定义:sleep()Thread类的一个静态方法。
    • 功能:它使当前正在执行的线程暂停执行指定的时间(以毫秒为单位),期间该线程不会释放任何锁,也就是说,如果一个线程调用了sleep()方法,它仍然持有之前获取的所有锁。
    • 使用场景:当你希望线程暂时停止执行一段时间,而不涉及线程间的协作时可以使用sleep()。例如,在模拟延迟或定时任务中。
      wait() 释放锁:
    • 定义:wait()Object类的一个实例方法。
    • 功能:它必须与同步块或同步方法一起使用,并且会释放当前对象的锁。当一个线程调用某个对象的wait()方法时,这个线程会被加入到该对象的等待队列中并进入等待状态,直到另一个线程调用同一个对象的notify()notifyAll()方法来唤醒它。
    • 使用场景:主要用于线程之间的协作,比如生产者-消费者问题中,用来协调多个线程对共享资源的访问。
  25. 递增有序表求平均查找长度,l1是平均查找成功长度,l2是平均查找不成功长度,求l1-l2
    l1 = (1 + 2 + … + n) / n = (n + 1) / 2;
    l2 = (1 + 2 + .. + n + n) / (n + 1) = n/2 + n / (n + 1);

编程题

简单,都做出来了

  1. 给定n个数据,每个数据是坐标位置和走的方向,每个人可以向左走和向右走,速度都一样,求多少人会相遇
  2. 有一个nxn的矩形,每次操作能给一个数加一,求最少操作多少次,使矩阵旋转90度、180度、270度都是一样的

选择题17递归求最大公约数(线段树思想)

线段树是一种二叉树数据结构,用于高效解决区间查询问题(如求区间和、最大值、最小值、GCD等)。

  • 每个节点代表一个区间的信息(如 [l, r] 的 GCD)。
  • 叶子节点存储单个元素的值。
  • 非叶子节点存储子区间合并后的信息(如左右子树的 GCD)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <vector>
#include <algorithm>
using namespace std;

vector<int> arr; // 输入数组
vector<int> tree; // 线段树

// 计算 GCD(注意处理 0 的情况)
int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}

// 递归构建线段树
void build(int node, int l, int r) {
if (l == r) {
tree[node] = arr[l];
return;
}
int mid = (l + r) / 2;
build(2 * node, l, mid); // 左子树
build(2 * node + 1, mid + 1, r); // 右子树
tree[node] = gcd(tree[2 * node], tree[2 * node + 1]); // 合并 GCD
}

// 递归查询区间 [ql, qr] 的 GCD
int query(int node, int l, int r, int ql, int qr) {
// 当前区间与查询区间无交集
if (qr < l || ql > r) {
return 0; // 中性值(gcd(x, 0) = x)
}
// 当前区间完全包含在查询区间内
if (ql <= l && r <= qr) {
return tree[node];
}
int mid = (l + r) / 2;
// 根据查询区间与 mid 的关系,决定递归方向
if (qr <= mid) {
return query(2 * node, l, mid, ql, qr); // 只需查左子树
} else if (ql > mid) {
return query(2 * node + 1, mid + 1, r, ql, qr); // 只需查右子树
} else {
// 查询区间横跨 mid,需合并左右子树的结果
int left_gcd = query(2 * node, l, mid, ql, mid);
int right_gcd = query(2 * node + 1, mid + 1, r, mid + 1, qr);
return gcd(left_gcd, right_gcd);
}
}

// 初始化线段树
void init() {
int n = arr.size();
tree.resize(4 * n); // 线段树大小为 4n
build(1, 0, n - 1); // 根节点从 1 开始
}