一面
算法
上来就是算法题
力扣原题 删除字符使频率相同
简单题 不过通过率只有24%
什么罐头我说
暴力方法很好写 不过当时直接开始写优化的方法 所以花了很长时间
复盘
// 暴力方法
class Solution {
public:
bool isEqual(unordered_map<char, int> c_frac){
int f = c_frac.begin()->second;
for (auto p:c_frac){
if (p.second != f){
return false;
}
}
return true;
}
bool equalFrequency(string word) {
// 遍历每个可能的删除字符
for (int i = 0; i < word.size(); i ++){
unordered_map<char, int> c_frac;
for (int j = 0; j < word.size(); j ++){
if (i != j){
c_frac[word[j]] ++;
}
}
// 检查删除字符后每个字符出现的频率是否相同
if (isEqual(c_frac)){
return true;
}
}
return false;
}
};
优化方法
实际上如果频率的个数大于2 那么一定不满足条件
如果频率的个数等于2 那么需要检查两个频率是否相等
如果频率的个数等于1 那么一定满足条件
class Solution {
public:
bool equalFrequency(string word) {
unordered_map<char, int> c_frac;
for (auto c:word){
c_frac[c] ++;
}
vector<int> frac;
for (auto p:c_frac){
frac.push_back(p.second);
}
sort(frac.begin(), frac.end());
// 只有一个
// 如果除了最后一个全相等 最后一个比其他多了1个 删除最后一个多的
// 如果最小的只有一个 并且其他全相等 删除第一个
return frac.size() == 1
||
frac[0] == 1 && equal(frac.begin() + 2, frac.end(), frac.begin() + 1)
||
frac[frac.size() - 1] == frac[frac.size() - 2] + 1 && equal(frac.begin() + 1, frac.end() - 1, frac.begin());
}
};
python基础
面试官问我简历上写的python和java,写算法有用cpp,希望我被问哪方面的(
python基本的集合类
list dict set tuple(没打上来 因为的确不怎么注意这个) 答字符串被认为是列表的一种
面试官强调说tuple是非常pythonic
的一个集合类
tuple和list的区别
tuple的元素不可变
list和dict区别
先说了一下list和dict的共同点 list实际上也是一个hash,一个索引映射到一个元素
不同点就是 list的元素存储的都是指针 大小都是相同的 而dict是变长的 每个元素大概率是不相同的
答这么多 实际上没有在点子上
面试官说自己问的太宏大了( 他只是希望我回答 dict是无序的 list有序的
难绷的 是我自己没有搞清楚二者最关键的区别
复盘
dict使用哈希函数将 key 映射到存储位置 不保证顺序 因此是无序的
list是一个顺序存储的数组结构,内部使用连续的空间存储元素指针
面相对象
继承是什么 java和python的继承有什么不同
假设代码中的一些类有一些相同的方法和属性 如果不使用继承 那么这些方法和属性只能放在各个类中 导致代码非常冗余
有个办法就是将共同的方法和属性抽象泛化到一个父类中,子类继承父类来减少代码冗余
java和python的继承除了语法不同(java是通过extends
关键字 python是括号)之外
java只有单继承 python支持多继承(class C(A, B):
)
MRO (Method Resolution Order) python多继承的解析顺序
没答上来
python支持多继承 就需要处理一些父类方法冲突的问题 比如两个继承的父类中有名字相同的方法或者属性
c3算法
- 子类优先原则:子类在父类前面
- 从左到右原则:多个父类时保持声明顺序
- 单调性原则:如果 C 的 MRO 中 A 在 B 前面,那么所有继承 C 的类的 MRO 中,A 也必须在 B 前面
工程
fastapi 处理报错的全局中间件
之前并没有详细了解中间件的概念 但是知道有个东西做这样的事情
回答的是有一个exception_handler
的装饰器 可以捕获异常
在FastAPI中,定义中间件通常是通过装饰器或在应用实例上添加中间件函数来实现的。中间件的设计使得它们可以灵活地插入到请求-响应的生命周期中,从而实现复杂的请求处理逻辑。
复盘
fastapi的中间件函数有request
和response
两个参数
主要有before_request
和after_request
两种
其次还有http
方法 可以对特定的http方法进行处理
spring boot 类似的中间件
回答了类似的报错处理中间件和访问拦截器 还说了AOP
复盘
spring boot 的中间件和fastapi的中间件是类似的 都是插入到请求-响应的生命周期中
spring中主要有filter、interceptor、AOP和exceptionHandler四种
其中filter是servlet中的概念 拦截请求和响应
interceptor是spring中的概念 拦截请求
AOP是spring中的概念 面向切面编程
exceptionHandler是spring中的概念 处理报错
数据库
数据库优化查询
建立索引 比如people表中的age字段
对age建立索引 mysql会建立一个新的树 将age作为key 将对应的主键放在叶子结点作为value
在根据age进行查询的时候 直接通过树进行查找 这样就大大提高了查询效率
redis常用数据结构
string、list、hash、set、zset(sorted set)
说了java项目使用redis存邮箱的验证码 限流等
python装饰器和java注解
python的装饰器是什么
装饰器是用来增强函数或方法的功能
可以在执行函数前或后执行一些操作
和java的aop类似
fastapi的项目使用装饰器来完成redis存缓存
java的注解是什么
注解是用来给类、方法、属性等添加一些额外的信息
分为编译时注解和运行时注解
运行时注解使用反射
机制,反射允许程序在运行时获取类的信息并操作类的属性和方法。比如@Autowired注解,Spring容器会在运行时通过反射找到被注解的属性,并注入对应的实例。一般运行时注解比较常用。
编译时注解使用apt
(Annotation Processing Tool)工具,在编译阶段处理注解并生成新的代码。比如Lombok的@Data注解会在编译时生成getter/setter方法。相比运行时注解,编译时注解不会带来运行时的性能开销,但功能相对有限。
反射是Java提供的一种机制,允许程序在运行时动态地获取类的信息(包括类的属性、方法、构造器等),并且可以操作这些信息。