博客记录-day120-ACM输入输出+MySQL,rabbitMQ,设计模式面试题

135 阅读11分钟

一、ACM模式

1、多行输入,每行两个整数

image.png

import java.lang.*;
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while (in.hasNextInt()) {
            int a = in.nextInt();
            int b = in.nextInt();
            System.out.println(a + b);
        }
    }
}

2、多组数据,每组第一行为n, 之后输⼊n行两个整数

image.png

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner scanner=new Scanner(System.in);
        while(scanner.hasNext()){
            int n=scanner.nextInt();
            for(int i=0;i<n;i++){
                int a=scanner.nextInt();
                int b=scanner.nextInt();
                System.out.println(a+b);
            }
        }    
    }
}

3、若干行输入,每行输入两个整数,遇到特定条件终止

image.png

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner scanner=new Scanner(System.in);
        while(scanner.hasNext()){
            int a=scanner.nextInt();
            int b=scanner.nextInt();
            if(a==0&&b==0){
                break;
            }
            System.out.println(a+b);
        }
    }
}

4、若干行输入,遇到0终止,每行第⼀个数为N,表示本行后面有N个数

image.png

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            int n = scanner.nextInt();
            if (n == 0) {
                break;
            }
            int sum = 0;
            for (int i = 0; i < n; i++) {
                sum += scanner.nextInt();
            }
            System.out.println(sum);
        }
    }
}

5、多组n行数据,每行先输入一个整数N,然后在同一行内输入 M个整数,每组输出之间输出一个空行。

image.png

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNextLine()) {
            int N = sc.nextInt();
            // 每组有n⾏数据
            while (N-- > 0) {
                int M = sc.nextInt();
                int sum = 0;
                // 每⾏有m个数据
                while (M-- > 0) {
                    sum += sc.nextInt();
                }
                System.out.println(sum);
                if (N > 0) System.out.println();
            }
        }
    }
}

6、多组测试样例,每组输入数据为字符串,字符用空格分隔,输出为小数点后两位

image.png

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        Map<String, Integer> map = new HashMap<>();
        map.put("A", 4);
        map.put("B", 3);
        map.put("C", 2);
        map.put("D", 1);
        map.put("F", 0);
        while (scanner.hasNextLine()) {
            String[] s = scanner.nextLine().split(" "); // 分割字符串
            double score = 0.0;
            boolean invalid = false; // 标记有无特殊字母(非ABCDF)出现
            for (int i = 0; i < s.length; i++) {
                if (!map.containsKey(s[i])) {
                    invalid = true;
                    break;
                }
                score += map.get(s[i]);
            }
            if (invalid) {
                System.out.println("Unknown");
            } else {
                System.out.printf("%.2f\n", score / s.length); // 保留2位
            }
        }
    }
}

1. java输出总结

1. System.out
  • 类型PrintStream(继承自OutputStream

  • 特点

    • 自动刷新缓冲区(当换行\nprintln()调用时)
    • 继承PrintStream,支持多种输出方法
  • 常用方法

    System.out.print("文本");    // 输出文本不换行
    System.out.println("文本");   // 输出文本并换行
    System.out.printf("格式", args); // 格式化输出(类似C语言printf)
    
2. String.format()
  • 静态方法:返回格式化后的字符串

    String formatted = String.format("%d年%d月%d日", 2023, 10, 1);
    System.out.println(formatted); // 输出:2023年10月1日
    
3. printf() 方法
  • 直接输出格式化字符串

    System.out.printf("%.2f%%\n", 0.95); // 输出:95.00%
    
4. 占位符与格式说明符
占位符说明示例
%d整数%d → 123
%f浮点数(默认6位小数)%f → 3.141593
%s字符串%s → "Hello"
%n换行符自动换行
%tx日期时间格式%tF → 2023-10-01

2. String ↔ 基本类型

  • String.valueOf()

    int num = 10;
    String str = String.valueOf(num); // "10"
    
  • Integer.parseInt()

    int num = Integer.parseInt("123"); // 123
    

7、多组测试用例,第一行为正整数n, 第二行为n个正整数,n=0 时,结束输入,每组输出结果的下面都输出一个空行

image.png

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            int size = scanner.nextInt();
            if (size == 0) {
                break;
            }
            // 创建list
            ArrayList<Integer> list = new ArrayList<>();
            // 添加数据到list中
            for (int i = 0; i < size; i++) {
                int num = scanner.nextInt();
                list.add(num);
            }
            int sum=0;
            for (int i = 0; i < list.size(); i++) {
                sum+=list.get(i);
            }
            sum=sum/size;
            int res=0;
            for (int i = 0; i < list.size(); i++) {
                res+=Math.abs(list.get(i)-sum) ;
            }
            System.out.println(res/2);
            System.out.println();
        }
    }
}

8、瓶盖换饮料

image.png

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextLine()) {
            int m = scanner.nextInt(), k = scanner.nextInt();
            if (m == 0 && k == 0) break;
            int time = (m - 1) / (k - 1) + m;

            System.out.println(time);
        }
    }
}

二、语雀-MySQL面试题

1、有了关系型数据库,为什么还需要NOSQL?

✅有了关系型数据库,为什么还需要NOSQL?

image.png

image.png

2、InnoDB和MyISAM有什么区别?

✅InnoDB和MyISAM有什么区别?

image.png

3、char和varchar的区别?

✅char和varchar的区别?

image.png

4、MySQL 5.x和8.0有什么区别?

✅MySQL 5.x和8.0有什么区别?

image.png

5、为什么不建议使用多表join?

✅为什么大厂不建议使用多表join?

image.png

image.png

6、说一说MySQL一条SQL语句的执行过程?

✅说一说MySQL一条SQL语句的执行过程?

image.png

image.png

7、InnoDB的一次更新事务过程是怎么样的?

✅InnoDB的一次更新事务过程是怎么样的?

image.png

image.png

8、什么是脏读、幻读、不可重复读?

✅什么是脏读、幻读、不可重复读?

image.png

9、InnoDB如何解决脏读、不可重复读和幻读的?

✅InnoDB如何解决脏读、不可重复读和幻读的?

image.png

10、事务隔离级别怎么实现的?

MySQL 的事务隔离级别通过其存储引擎(主要是 InnoDB)的底层机制实现,核心在于 多版本并发控制(MVCC)锁机制 的结合。以下是各隔离级别的实现原理及关键技术:


1. 事务隔离级别与问题

隔离级别脏读不可重复读幻读说明
读未提交✔️✔️✔️最低级别,无锁
读已提交✔️✔️基于 MVCC 的快照读
可重复读✔️MVCC + 间隙锁防幻读
串行化全表锁/行锁,强制顺序执行

2. 实现机制的核心技术

(1) MVCC(多版本并发控制)

核心思想:为每一行数据维护多个版本(快照),通过版本号或时间戳管理数据的可见性。

关键结构

  • Undo Log:存储事务未提交前的数据版本,用于回滚和快照读。
  • Redo Log:保证数据持久化,崩溃恢复时重做未提交的事务。
  • 版本链:每个行数据关联一个版本链,事务根据 Read View 的规则选择可见版本。
(2) 锁机制

共享锁(S Lock):允许读操作,阻止其他事务加排他锁。

  • 排他锁(X Lock):允许写操作,阻止其他事务加任何锁。
  • 意向锁:表级锁,表示后续操作的范围(意向共享/排他)。
  • 间隙锁(Gap Lock):锁定索引区间,防止插入幻读(仅 InnoDB)。

3. 各隔离级别的实现细节

(1) 读未提交(Read Uncommitted)
  • 实现:使用 非锁定读(Non-Locking Read),直接读取当前最新数据。
  • 风险:可能读取到未提交的数据(脏读)、不可重复读、幻读。
  • 适用场景:极少使用,主要用于调试或高性能要求低且容忍不一致的场景。
(2) 读已提交(Read Committed)

实现

  • MVCC 快照读:事务启动时生成 Read View,仅读取已提交事务的版本。
  • 非锁定读:默认使用 MVCC 版本,无需显式加锁。
  • 风险:仍可能因多版本共存导致 不可重复读(两次读同一行结果不同)。
  • 优化:可通过 SET TRANSACTION ISOLATION LEVEL READ COMMITTED; 启用。
(3) 可重复读(Repeatable Read)

实现

  • MVCC 快照读:事务开始时固定 Read View,全程使用该快照。
  • 间隙锁:对范围查询(如 SELECT ... WHERE id BETWEEN 100 AND 200)自动加间隙锁,防止其他事务插入新数据导致幻读。
  • 风险:高并发下锁竞争加剧,性能下降。
  • 示例:两次查询同一行数据结果一致,因始终读取事务开始时的快照。
(4) 串行化(Serializable)

实现

  • 强制串行化:对所有操作加 表级排他锁(Table Lock)行级锁,确保事务顺序执行。
  • 范围查询加间隙锁:与可重复读类似,但锁粒度更粗。

风险:严重降低并发性能,仅用于必须完全避免幻读的场景。


4. 幻读的解决策略

  • 可重复读:通过 间隙锁 锁定查询条件涉及的索引区间,阻止新数据插入。
  • 串行化:通过 表级锁 阻止其他事务修改数据。
  • 读已提交:无法避免幻读,需依赖应用层处理(如使用唯一索引)。

三、语雀-RabbitMQ面试题

1、rabbitMQ的整体架构是怎么样的?

✅rabbitMQ的整体架构是怎么样的?

image.png

image.png

2、RabbitMQ是怎么做消息分发的?

✅RabbitMQ是怎么做消息分发的?

1. 简单模式

image.png

2. 工作队列模式

image.png

3. 发布订阅模式

image.png

4. 路由模式

image.png

5. 主题模式

image.png

3、rabbitMQ如何实现延迟消息?

✅rabbitMQ如何实现延迟消息?

1. 死信队列

image.png

4、什么是RabbitMQ的死信队列?

✅什么是RabbitMQ的死信队列?

image.png

image.png

5、RabbitMQ 是如何保证高可用的?

image.png

1. 普通集群

image.png

image.png

2. 镜像集群

image.png

6、RabbitMQ如何实现消费端限流

✅RabbitMQ如何实现消费端限流

image.png

7、RabbitMQ如何防止重复消费

image.png

1. 接口幂等

image.png

image.png

8、如何保障消息一定能发送到RabbitMQ

image.png

9、RabbitMQ如何保证消息不丢

✅RabbitMQ如何保证消息不丢

image.png

1. 队列和交换机的持久化

image.png

2. 持久化消息

image.png

3. 消费者确认机制

image.png

10、介绍下RabbitMQ的事务机制

image.png

四、语雀-设计模式面试题

0、代理模式在项目中应用

1. 工厂模式(Factory Pattern)

工厂模式在项目中主要用于创建复杂对象,隐藏创建逻辑,通过统一接口来指向新创建的对象。

DefaultTreeFactory

LogicTreeTest.java中可以看到工厂模式的应用:

@Resource
private DefaultTreeFactory defaultTreeFactory;

@Test
public void test_tree_rule() {
    // 构建规则树
    // ...
    
    // 使用工厂创建决策树引擎
    IDecisionTreeEngine treeEngine = defaultTreeFactory.openLogicTree(ruleTreeVO);
    
    // 使用决策树处理业务
    DefaultTreeFactory.StrategyAwardVO data = treeEngine.process("xiaofuge", 100001L, 100, null);
}

工厂类DefaultTreeFactory负责创建决策树引擎对象,客户端不需要关心具体实现细节,只需要通过工厂获取对象即可。

策略装配工厂

RaffleStrategyTest.java中:

@Resource
private IStrategyArmory strategyArmory;

@Before
public void setUp() {
    // 策略装配 100001、100002、100003
    log.info("测试结果:{}", strategyArmory.assembleLotteryStrategy(100001L));
    log.info("测试结果:{}", strategyArmory.assembleLotteryStrategy(100006L));
}

IStrategyArmory作为工厂接口,负责装配和创建抽奖策略对象。

2. 代理模式(Proxy Pattern)

代理模式在项目中主要用于控制对其他对象的访问,增强原有对象的功能。

示例:数据库路由代理

AwardRepository.java中:

@Resource
private IDBRouterStrategy dbRouter;

@Override
public void saveUserAwardRecord(UserAwardRecordAggregate userAwardRecordAggregate) {
    // ...
    try {
        dbRouter.doRouter(userId);  // 代理路由到特定数据库
        transactionTemplate.execute(status -> {
            // 执行数据库操作
            // ...
        });
    } finally {
        dbRouter.clear();
    }
    // ...
}

IDBRouterStrategy作为代理,控制数据库的路由访问,增强了原有数据库操作的功能,实现了分库分表的能力。

3. 模板模式(Template Pattern)

模板模式在项目中定义了算法的骨架,将一些步骤延迟到子类中实现。

示例:BaseEvent抽象类

BaseEvent.java中:

@Data
public abstract class BaseEvent<T> {
    // 定义抽象方法,由子类实现
    public abstract EventMessage<T> buildEventMessage(T data);
    public abstract String topic();
    
    // 定义消息结构
    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    public static class EventMessage<T> {
        private String id;
        private Date timestamp;
        private T data;
    }
}

子类实现示例(SendAwardMessageEvent.java):

@Component
public class SendAwardMessageEvent extends BaseEvent<SendAwardMessageEvent.SendAwardMessage> {
    @Value("${spring.rabbitmq.topic.send_award}")
    private String topic;

    @Override
    public EventMessage<SendAwardMessage> buildEventMessage(SendAwardMessage data) {
        return EventMessage.<SendAwardMessage>builder()
                .id(RandomStringUtils.randomNumeric(11))
                .timestamp(new Date())
                .data(data)
                .build();
    }

    @Override
    public String topic() {
        return topic;
    }
    
    // 内部消息类定义
    // ...
}

BaseEvent定义了事件处理的骨架,子类实现具体的消息构建和主题定义。

4. 策略模式(Strategy Pattern)

策略模式在项目中定义了一系列算法,并使这些算法可以互相替换,让算法的变化独立于使用算法的客户端。

示例:抽奖策略

RaffleStrategyTest.java中:

@Resource
private IRaffleStrategy raffleStrategy;

@Test
public void test_performRaffle() throws InterruptedException {
    RaffleFactorEntity raffleFactorEntity = RaffleFactorEntity.builder()
            .userId("xiaofuge")
            .strategyId(100006L)
            .build();

    // 执行抽奖策略
    RaffleAwardEntity raffleAwardEntity = raffleStrategy.performRaffle(raffleFactorEntity);
}

项目中还有规则链和规则树的实现:

@Resource
private RuleWeightLogicChain ruleWeightLogicChain;
@Resource
private RuleLockLogicTreeNode ruleLockLogicTreeNode;

这些都是策略模式的应用,通过不同的策略实现,可以灵活切换抽奖规则、权重计算等算法。

总结

该项目通过多种设计模式的组合使用,构建了一个灵活、可扩展的抽奖系统:

  1. 工厂模式:用于创建复杂对象,如决策树引擎、抽奖策略等
  2. 代理模式:用于增强功能,如数据库路由代理
  3. 模板模式:用于定义算法骨架,如事件处理基类
  4. 策略模式:用于实现可替换的算法,如抽奖策略、规则链等

这些设计模式的应用使得系统具有良好的可维护性和可扩展性,能够应对业务需求的变化。

1、三种工厂模式的区别和特点

✅三种工厂模式的区别和特点

image.png

image.png

image.png

1. 简单工厂模式

image.png image.png

2. 工厂方法模式

image.png

image.png

3. 抽象工厂模式

image.png

image.png

2、什么是不可变模式,有哪些应用?

image.png

image.png

3、什么是享元模式,有哪些具体应用?

✅什么是享元模式,有哪些具体应用?

image.png

4、String的设计,用到了哪些设计模式?

✅String的设计,用到了哪些设计模式?

image.png

5、什么是责任链模式,有哪些应用?

✅什么是责任链模式,有哪些应用?

image.png

6、什么是状态模式,有哪些应用?

✅什么是状态模式,有哪些应用?

image.png

7、策略模式和if-else相比有什么好处?

✅策略模式和if-else相比有什么好处?

image.png

1. 策略+工厂+模板方法模式实际应用

image.png

image.png

image.png

image.png

image.png

8、什么是观察者模式,有哪些应用?

✅什么是观察者模式,有哪些应用?

image.png

9、什么是代理模式,有哪些应用?

✅什么是代理模式,有哪些应用?

image.png

image.png

10、什么是模板方法模式,有哪些应用?

✅什么是模板方法模式,有哪些应用?

image.png