一、力扣
1、最小栈
class MinStack {
ArrayDeque<int[]> stack;
public MinStack() {
stack=new ArrayDeque<>();
stack.push(new int[]{0, Integer.MAX_VALUE});
}
public void push(int val) {
int[] ans=stack.peek();
stack.push(new int[]{val,Math.min(ans[1],val)});
}
public void pop() {
stack.pop();
}
public int top() {
return stack.peek()[0];
}
public int getMin() {
return stack.peek()[1];
}
}
2、简化路径
在 Java 中,String.split() 方法根据正则表达式分割字符串时,可能产生空字符串,常见于分隔符位于字符串首尾、存在连续分隔符或未正确转义正则元字符的情况(如 .、| 等)。例如,",a,b,c,".split(",") 会生成包含首尾空串的数组 ["", "a", "b", "c", ""],而连续分隔符(如 "a,,b")会生成空元素 ["a", "", "b"]。
class Solution {
public String simplifyPath(String path) {
ArrayDeque<String> stack=new ArrayDeque<>();
String[] ans=path.split("/");
for(var e:ans){
if(e.equals("..")){
if(!stack.isEmpty()) stack.pop();
}else{
if(e.length()>0&&!e.equals(".")){
stack.push(e);
}
}
}
StringBuilder res=new StringBuilder();
if(stack.isEmpty()){
res.append("/");
}else{
while(!stack.isEmpty()){
res.append("/");
res.append(stack.pollLast());
}
}
return new String(res);
}
}
3、 排序数组
class Solution {
Random random=new Random();
public int[] sortArray(int[] nums) {
int n=nums.length;
int left=0,right=n-1;
quicksort(nums,left,right);
return nums;
}
public void quicksort(int[] nums,int left,int right){
if(left>right) return;
int partition=left+random.nextInt(right-left+1);
swap(nums,left,partition);
int i=left+1,j=right;
while(true){
while(i<=j&&nums[i]<nums[left]) i++;
while(i<=j&&nums[j]>nums[left]) j--;
if(i>=j) break;
swap(nums,i,j);
i++;
j--;
}
swap(nums,left,j);
quicksort(nums,left,j-1);
quicksort(nums,j+1,right);
}
public void swap(int[] nums,int a,int b){
int temp=nums[a];
nums[a]=nums[b];
nums[b]=temp;
}
}
4、右旋字符串
关键点:nextInt 后面如果有nextLine,需要再一次nextLine。 一共反转三段字符串。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
in.nextLine();
String s = in.nextLine();
int len = s.length(); //获取字符串长度
char[] chars = s.toCharArray();
reverseString(chars, 0, len - n - 1); //反转前一段字符串,此时的字符串首尾是0,len - n - 1
reverseString(chars, len - n, len - 1); //反转后一段字符串,此时的字符串首尾是len - n,len - 1
reverseString(chars, 0, len - 1); //反转整个字符串
System.out.println(chars);
}
public static void reverseString(char[] ch, int start, int end) {
//异或法反转字符串,参照题目 344.反转字符串的解释
while (start < end) {
ch[start] ^= ch[end];
ch[end] ^= ch[start];
ch[start] ^= ch[end];
start++;
end--;
}
}
}
二、语雀-场景题
1、如何用Redis实现朋友圈点赞功能?
2、Redis的zset实现排行榜,实现分数相同按照时间顺序排序,怎么做?
✅Redis的zset实现排行榜,实现分数相同按照时间顺序排序,怎么做?
3、消息队列使用拉模式好还是推模式好?为什么?
4、如果让你实现一个RPC框架,会考虑用哪些技术解决哪些问题?
✅如果让你实现一个RPC框架,会考虑用哪些技术解决哪些问题?
5、如何解决消息重复消费、重复下单等问题?
5、你是如何进行SQL调优的?
6、索引失效的问题是如何排查的,有哪些种情况?
7、从B+树的角度分析为什么单表2000万要考虑分表??
3层高度的B+树最终的可存储数据量为: 1170 * 1170 * 16 = 21,902,400,即2000万!
8、InnoDB为什么不用跳表,Redis为什么不用B+树?
三、语雀-操作系统面试题
1、计算机打开电源操作系统做了什么?
2、同步、异步、阻塞、非阻塞怎么理解?
3、操作系统的IO模型有哪些?
4、如何理解select、poll、epoll?
select、poll 和 epoll 是 Linux 中用于 I/O 多路复用 的三种机制,核心目标是通过单线程高效管理多个文件描述符(如套接字)。
• select:最早实现,通过固定大小的位图标记文件描述符状态,存在性能瓶颈(需遍历所有 fd,且数量上限为 1024)。
• poll:改进版,改用动态数组存储 fd,取消了数量限制,但仍需线性遍历所有 fd 检测状态,效率随 fd 增多而下降。
• epoll:Linux 特有高效方案,采用事件驱动模型,通过内核与用户空间的共享内存传递就绪事件,仅需处理活跃的 fd(时间复杂度 O(1)),支持大规模并发连接。
简言之,三者本质均为异步通知机制,但 epoll 在高并发场景下性能显著优于前两者,成为现代网络编程的首选。
5、什么是零拷贝?
6、什么是分段和分页?
分段和分页是两种内存管理技术:分段将内存按逻辑功能划分为不同大小的连续区域(如代码段、数据段),便于模块化管理和灵活扩展,但易产生外部碎片;分页将内存和进程地址空间均划分为固定大小的页(如4KB),通过页表映射物理页框,减少碎片且支持虚拟内存,但可能造成内部碎片。分段强调逻辑结构,适合复杂程序需求;分页侧重物理高效性,是现代操作系统主流方案。
7、负载(Load)和CPU利用率之间有什么区别?
CPU 利用率关注的是资源的使用效率,而负载则关注的是服务的压力大小。