某银行 线上笔试

一、选择题

1.排序算法 是否稳定

稳定性定义:如果两个相等的元素在排序前后的相对位置不变,则称该排序算法是稳定的。

快希选堆不稳定(快排、希尔、选择、堆排序)

算法 稳定 备注
冒泡排序 ✅️ 相邻交换,相等不交换
插入排序 ✅️ 插入时相等元素不越过
归并排序 ✅️ 合并时左边优先
选择排序 交换可能打乱相等元素顺序
快速排序 分区交换不稳定
堆排序 堆化过程不稳定
希尔排序 分组插入,跨步长交换
计数排序 ✅️(稳定实现) 按顺序收集
奇数排序 ✅️ 稳定子排序保证

2.TCP/IP封装顺序,一台主机向另一台主机发送HTTP请求,数据从应用层—传输层—网络层—链路层,首部信息依次添加的顺序:TCP/UDP头部—IP头部—以太网头部

封装过程:应用层数据(HTTP报文)—传输层添加TCP/UDP头部—网络层添加IP头部—链路层添加以太网头部(含MAC地址)和尾部FCS。

OSI的七层模型:

  • 应用层:各种应用程序协议,比如HTTP、HTTPS、FTP、SOCKS安全套接字协议、DNS域名系统、GDP网关发现协议等。
  • 表示层:加密解密、转换翻译、压缩解压缩,比如LPP轻量级表示协议。
  • 会话层:不同机器上的用户建立和管理会话。比如SSL安全套接字层协议、TLS传输层安全协议、RPC远程过程调用协议等。
  • 传输层:接受上一层的数据,在必要时对数据进行分割并交给网络层,保证这些数据有效到达对端,比如TCP传输控制协议、UDP数据报协议。
  • 网络层:控制子网的运行:逻辑编址、分组传输、路由选择,比如IP、IPV6、SLIP等。
  • 数据链路层:物理寻址,同时将原始比特流转变为逻辑传输路线,比如XTP压缩传输协议、PPTP点对点隧道协议等。
  • 物理层:机械、电子、定时接口通信信道上的原始比特流传输,比如IEEE802.2等。

TCP/IP的四层网络模型:

  • 网络接口层:用于协作IP数据在已有网络介质上传输的协议,ARP地址解析协议(IP地址解析为MAC地址),RARP反向地址解析协议(MAC地址解析为IP地址)。
  • 网间层:对应网络层,负责数据的包装、寻址和路由。同时还包含网间控制报文协议ICMP用来提供网络诊断信息。IP,RIP,ICMP。
  • 传输层:对应传输层,提供两种端到端的通信服务。TCP提供可靠的数据流运输服务,UDP提供不可靠的用户数据报服务。
  • 应用层:对应应用层和表达出。Finger、Whois、FTP文件传输协议、Gopher、HTTP超文本传输协议、Telent远程终端协议、SMTP简单邮件传送协议、IRC因特网中继会话、NNTP网络新闻传输协议。

3.信号量。P,V的信号量初值S为2,当前值为2,哪个会唤醒进程(V后信号量值<=0,说明有进程在等待,需要唤醒)?

P操作:S减一,若S<0则阻塞,获取资源。

V操作:S加一,若S<=0则唤醒一个等待进程,释放资源。

一个线程 PV,两个线程 PV PV。

我们计算每个序列执行后的最终S值,并判断中间是否有V操作导致S<=0。

  • PPVPPV:P(2→1), P(1→0), V(0→1, 1>0不唤醒), P(1→0), P(0→-1阻塞), V(-1→0, 此时S=0<=0,唤醒一个) → 有唤醒。

  • PPVPVV:P(2→1), P(1→0), V(0→1), P(1→0), V(0→1), V(1→2) → 没有S<=0的情况,无唤醒。

  • PVPVPV:P(2→1), V(1→2), P(2→1), V(1→2), P(2→1), V(1→2) → 无阻塞无唤醒。

  • PVPPVV:P(2→1), V(1→2), P(2→1), P(1→0), V(0→1), V(1→2) → 无唤醒。

4.二叉树 先序遍历(根左右),中序遍历(左根右),后序遍历(左右根)

5.SQL,年龄最大的前3个人,SELECT * FROM person ORDER BY age DESC LIMIT 3;

6.IaaS、PaaS、Saas

  • IaaS(基础设施即服务):提供计算、网络、存储等基础资源。用户可部署任意软件,控制OS、存储、应用程序,支持自定义配置。虚拟机,云服务器。数据库服务、预装OS和应用属于IaaS吗?——如果是用户自己安装数据库,属于IaaS;如果是托管数据库服务(如RDS),则更接近PaaS。

  • PaaS(平台即服务):提供开发部署平台,用户只管应用,不管OS和中间件。数据库托管,如阿里云RDS。

  • SaaS(软件即服务):直接使用软件,如Gmail、钉钉。

7.数据库隔离级别:

隔离级别 脏读 不可重复读 幻读
读未提交 ✅ 可能 ✅ 可能 ✅ 可能
读已提交 ✅ 可能 ✅ 可能
可重复读 ✅ 可能(InnoDB的RR通过间隙锁避免了幻读)
串行化

并发事务会导致的问题:脏读(读到其他事务未提交的数据)、丢失修改(后写的覆盖先写的)、不可重复读(两次读取,结果不一样)、幻读(两次读取,行数不一样)。

8.设计模式

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

单例模式:单例对象的类必须保证只有一个实例存在,整个系统只能使用一个对象实例。不会频繁地创建和销毁对象,浪费系统资源。懒汉模式(非线程安全,用的时候再创建对象),饿汉模式(线程安全,提前就已经加载好的静态static对象),双重检查模式(线程安全,两次检查避免多线程造成创建了多个对象)。

(静态)工厂模式:建立一个工厂类,对实现了同一接口的一些类进行实例的创建。客户端只用知道参数就可以创建类;不易拓展。

抽象工厂模式:在简单工厂的基础上将未来可能需要修改的代码抽象出来,通过继承的方式让子类去做决定。只声明方法,具体的实现交给子类(子工厂)去实现。

建造者模式:将一个复杂对象的创建过程与其最终表示形式分离,使得同样的构建过程可以创建出不同结构或配置的对象。

代理模式:给某一个对象提供一个代理,并由代理对象控制对原对象的引用,重在访问权限的控制。能够协调调用者和被调用者,降低了系统的耦合度,可以灵活地隐藏和增加被代理对象的功能和服务;但程序性能没有直接调用性能高,提高了代码的复杂度。

多线程环境下的配置管理器,配置数据在整个应用程序中只有一份,首次访问是懒加载初始化,同时考虑线程安全与性能。——单例模式

9.继承:子类不可直接访问父类私有成员,需通过protected/public方法;子类可继承父类所有成员,可重写方法并扩大访问权限(但不能缩小);创建子类示例,先父类构造函数,子类构造器第一行隐式super()。

10.Transformer架构:Encoder(Self-Attention+FFN+Add&Norm),Decoder

11.寻址:指令中如何找到操作数(或操作数的地址)的方法。

操作数所在位置 指令中的地址码含义 示例(类似汇编) 特点
立即寻址 指令本身 操作数本身(常数) MOV AX, 1234H
直接寻址 内存 操作数的内存地址 MOV AX, [2000H]

寄存器直接寻址

(简称寄存器寻址)

寄存器 寄存器编号 MOV AX, BX
寄存器间接寻址 内存 寄存器中存放的是操作数的地址 MOV AX, [BX]
基址寻址 内存 基址寄存器 + 偏移量 MOV AX, [BX+100]

12.主键索引查询,主键索引(a,b,c),a=1且b>2 可以,a>2且b=9 不可以。

联合索引遵循最左前缀原则,范围查询(>, <, between, like 'xx%')会停止匹配后续列。

13.软件工程中的“方法”要素:过程、技术、工具、表示法。

软件工程三要素:

方法
  • 结构化方法:数据流图、E-R图、状态转换图等。

  • 面向对象方法:UML(用例图、类图、序列图等)、对象建模。

  • 敏捷方法:Scrum、极限编程(XP)、用户故事、测试驱动开发(TDD)。

  • 形式化方法:使用数学证明保证软件正确性(如安全关键系统)。

工具

设计建模:draw.io、Visio

编码开发:IDE(IntelliJ IDEA、Eclipse、VSCode)、Git、Maven/Gradle

测试:JUnit、Postman、Swagger

持续集成:GitLab CI、GitHub Actions

文档协作:Notion、Wiki、Markdown编辑器

过程

常见软件过程模型

  • 瀑布模型:需求→设计→编码→测试→维护,顺序进行。

  • 迭代/增量模型:分多个小循环,逐步交付功能。

  • 敏捷过程(Scrum、Kanban):短迭代、持续反馈、自适应调整。

  • DevOps:开发与运维一体化,强调持续交付、自动化部署。

  • RUP(Rational Unified Process):用例驱动、架构中心、迭代增量。

14.依赖倒置原则(DIP):高层模块不应该依赖低层模块,两者都应该依赖抽象;抽象不应该依赖细节,细节应该依赖抽象。面向接口编程,而非实现编程。降低耦合,提高扩展性。高层与低层的耦合——抽象接口+依赖注入

开闭原则(OCP):软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。需求变化导致的代码修改——抽象+多态扩展

里氏替换(LSP):子类型必须能够替换掉它们的父类型。即程序中所有使用父类对象的地方,都可以透明地替换成子类对象,而不会改变程序的正确性。继承的正确使用

15.栈:先入后出;队列:先入先出

二、编程题

1.Java计算,double与int乘,输出保留两位小数,开n次方

double与int乘:自动类型提升为double。

保留两位小数

  • String.format("%.2f", value)

  • BigDecimal.setScale(2, RoundingMode.HALF_UP)

Math:

  • a的b次方:使用Math.pow(a, 1.0/n)。注意:Math.pow(8, 1.0/3) 得到2.0。

  • 绝对值:abs(x) 支持int/long/float/double

  • 最大/最小值:max(a,b)/min(a,b)

  • 平方根:sqrt(x)

  • 随机数:Math.random()   // [0.0, 1.0) 的double

  • 指数与对数:

    Math.exp(x);     // e^x
    Math.log(x);     // 自然对数 ln x
    Math.log10(x);   // 以10为底的对数
  • 取整:

    double x = 3.6;
    Math.ceil(x);    // 向上取整 → 4.0
    Math.floor(x);   // 向下取整 → 3.0
    Math.round(x);   // 四舍五入 → 4(返回long)
    Math.rint(x);    // 四舍五入取整(返回double,逢 .5 取偶数)

  • BigDecimal:用于精确货币计算,避免浮点误差。

    • 比较:a.compareTo(b) > 0 表示 a > b。=0表示a=b,不要用equals比较2.0和2.00(scale不同返回false)

    • 加减乘除:a.add(b),a.subtract(b)a.multiply(b),a.divide(b, 2, RoundingMode.HALF_UP)。

    • 取负:a.negate()

    • 绝对值:a.abs()

    • stripTrailingZeros() – 去除末尾多余的0

    • toPlainString() – 返回不带指数形式的字符串

    • scale() – 返回小数位数

  • 全额降序排序 Comparator

    List<Item> list = ...;
    list.sort((o1, o2) -> o2.getAmount().compareTo(o1.getAmount()));
    // 或使用 Comparator.reverseOrder()

2.String

  • String取子串

    • substring(beginIndex, endIndex):注意 endIndex 是不包含的。

    • 取最后4个字符:str.substring(str.length() - 4)

    • 取前3个字符:s.substring(0, 3);

  • 大小写转换str.toUpperCase();str.toLowerCase()

  • 转换与修改:String不可变,返回新字符串

String upper = s.toUpperCase();
String lower = s.toLowerCase();
String trimmed = s.trim();          // 去除首尾空白
String replaced = s.replace('l','w');   // 替换字符
String replacedAll = s.replaceAll("\\d+", "#"); // 正则替换
String[] parts = s.split(",");       // 分割
String sub = s.substring(2, 5);      // [2,5) 子串
String joined = String.join("-", "a","b","c"); // "a-b-c"
  • 格式化

String fmt = String.format("姓名:%s,年龄:%d", "张三", 25);
System.out.print(fmt);
//姓名:张三,年龄:25

// 或使用 printf
System.out.printf("%.2f\n", 3.14159);
//3.14
  • 查询与判断:

方法 示例 说明
length() s.length() 字符个数
charAt(int) s.charAt(0) 获取指定位置字符
indexOf(String) s.indexOf("lo") 子串首次出现位置
lastIndexOf(String) 最后一次出现位置
contains(CharSequence) s.contains("he") 是否包含子串
startsWith(String) 是否以某前缀开头
endsWith(String) 是否以某后缀结尾
isEmpty() / isBlank() 是否为空或仅空白(Java 11+)
equals(Object) s1.equals(s2) 内容相等
equalsIgnoreCase(String) 忽略大小写比较
  • StringBuilder:线程不安全,效率高(单线程推荐)

  • StringBuffer:线程安全,效率略低(多线程环境)

3.格式化语法

格式化字符串包含普通文本格式说明符(以 % 开头)。

基本语法%[参数索引$][标志][宽度][.精度]转换符

常见转换符(必须掌握)

转换符 说明 示例
%s 字符串 "姓名:%s" → 填入 String
%d 十进制整数 "年龄:%d" → 填入 int / long
%f 浮点数(十进制) "价格:%.2f" → 保留两位小数
%e / %E 科学计数法 "科学计数:%e"
%x / %X 十六进制整数 "十六进制:%x"
%o 八进制整数 "八进制:%o"
%c 字符 "等级:%c" → char
%b 布尔值 "是否通过:%b" → true/false
%n 平台独立的换行符 相当于 \n 但跨平台更好
%% 输出百分号本身 "成功率:100%%" → 输出 "100%"

常用标志与宽度(让输出更整齐)

标志 作用 示例
- 左对齐(默认右对齐) "%-5d" → 整数占5格,左对齐
0 数字前面补0 "%05d" → 5 → 00005
, 数字千位分隔符 "%,d" → 1234567 → 1,234,567
+ 强制显示正号 "%+d" → 5 → +5
( 负数用括号括起来(财务风格) "%(d" → -5 → (5)
空格 正数前加空格,负数前加负号 "% d"

宽度:最小字符数,不够则用空格填充(默认右对齐)。
精度

  • 对于 %f:小数点后位数

  • 对于 %s:最大字符数(截断)

// 左对齐,宽度10,保留2位小数
System.out.printf("%-10.2f", 123.456);  // 输出 "123.46    "(后面有空格)

// 补零,宽度6
System.out.printf("%06d", 42);          // 输出 "000042"

// 千位分隔符 + 两位小数
System.out.printf("%,.2f", 1234567.891); // 输出 "1,234,567.89"

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐