秋招突击——8/6——万得数据面试总结

news2024/11/24 11:43:44

文章目录

    • 引言
    • 正文
      • 面经整理一
        • 1、讲一下java的多态,重载,重写的概念,区别
        • 2、说一下Java的数组,链表的结构,优缺点
        • 3、创建java线程的方式有哪些,具体说说
        • 4、创建线程池呢、每个参数的意义
        • 5、通过那几种方式保证线程安全
        • 6、jvm加载
        • 7、了解数据库事物?特性?
        • 8、怎么提高sql查询性能 (只说了添加索引,分库分表)
        • 9、String特性是什么
        • 10、redis数据类型
        • 11、redis持久化 答了(AOF,RDB)接着问了他们之间的区别
      • 面经整理二
        • 1、spring是怎么实现aop的
        • 2、aop的原理
        • 3、用户通过客户端或者浏览器发送请求,在springboot框架下是如何接收这个请求、解析并向下透传到control层的
        • 4、mysql的底层结构
        • 5、索引分为哪几个类型
        • 6、以非聚簇索引作为一个查询条件,去获取到整条记录的中间过程是什么
        • 7、建索引要满足哪些原则
        • 8、hashmap扩容的过程
        • 9、synchronized和可重入锁有哪些区别
        • 10、线程安全的集合concurrenthashmap是如何保证线程安全的
        • 11、java的内存分布
        • 12、1.8的jvm默认的两个垃圾回收器是哪两个,区别是什么
        • 13、有一个web服务的接口,刚上线的时候没有什么问题,突然一段时间后客户端调用该接口,该接口的反馈都是超时,如何定位这个服务的问题
      • 正式面试
        • 第一面
          • A面
          • B面
            • ThreadLocal了解吗?如何防止内存泄漏?
            • 如何对复杂对象进行深拷贝?
            • SpringAOP的实现过程
    • 笔试
    • 总结

引言

  • 今天要面试万得数据,上午在整理项目相关的问题,看相关的代码,现在整理一下面经,毕竟下午两点钟就要开始的!

正文

面经整理一

作者:网抑云八级选手
链接:https://www.nowcoder.com/feed/main/detail/a44af7a275754bc0a200fcc9778d64c0?sourceSSR=search
来源:牛客网

1、讲一下java的多态,重载,重写的概念,区别

多态

  • 同一个接口或者基类可以指向不同的实现或子类对象,编写更加通用和灵活的代码
    • 编译时多态(静态多态):通过方法重载实现。
    • 运行时多态(动态多态):通过方法重写和接口实现。

重载

  • 重载是指在同一个类中,可以有多个同名的方法但它们的参数列表不同(参数的数量或类型不同)。重载是编译时多态的一种形式
  • 主要特点
    • 方法名相同
    • 参数列表不同(参数的数量或类型不同)。
    • 可以有不同的返回类型
    • 可以有不同的访问修饰符

重写

  • 重写是指子类提供了与父类中同名方法的实现
  • 重写是运行时多态的一种形式。通过重写,子类可以提供特定的实现,而不是使用父类的实现
  • 主要特点
    • 方法名、参数列表、返回类型必须相同。
    • 访问修饰符不能比父类的更严格(可以更宽松)。
    • 子类方法不能比父类方法抛出更多或更广泛的异常。

区别

  • 多态:同一个接口或者基类可以多种实现
  • 重载:在同一个类中,同名方法有不同的参数列表,是编译时多态
  • 重写:子类提供与父类同名方法的实现,运行时多态
2、说一下Java的数组,链表的结构,优缺点

数组

  • 一种线性数据结构,用于存储相同类型元素的集合
  • 数组在内存中是连续分配的,所有元素的大小相同,可以通过索引快速访问。
  • 优点
    • 快速访问:由于数组元素在内存中是连续存储的,可以通过索引在O(1)时间复杂度内直接访问任意元素。
    • 节省内存:没有额外的存储开销(如指针)。
    • 缓存友好:由于数组元素连续存储,使用缓存时效率更高。
  • 缺点
    • 固定大小:数组的大小在创建时必须确定,之后不能改变。这可能导致内存浪费或不够用。
    • 插入和删除效率低:在数组中插入或删除元素需要移动大量元素,时间复杂度为O(n)。
    • 不适合频繁插入和删除操作:由于上述原因,数组不适合在中间频繁进行插入和删除操作。

链表

  • 一种线性数据结构,由一系列节点(Node)组成每个节点包含数据和指向下一个节点的引用(或指针)

  • 根据节点之间的连接方式,链表可以分为单向链表(Singly Linked List)和双向链表(Doubly Linked List)

  • 优点

    • 动态大小:链表可以根据需要动态增长或缩小,不需要预先分配固定大小。
    • 插入和删除操作高效:在链表中插入或删除元素不需要移动其他元素,只需修改指针即可,时间复杂度为O(1)(在已知位置的情况下)。
    • 适用于频繁插入和删除操作:尤其是在中间插入或删除时,链表比数组更高效。
  • 缺点

    • 访问速度慢:由于无法通过索引直接访问元素,必须从头节点开始逐个遍历,时间复杂度为O(n)。
    • 额外的内存开销:每个节点除了存储数据,还需要存储指针,这会占用额外的内存。
    • 缓存不友好:由于链表元素在内存中不是连续存储的,使用缓存时效率较低。
3、创建java线程的方式有哪些,具体说说

继承Thread类

  • 结构
    • 通过继承Thread类并重写run方法来创建线程
  • 步骤
    • 创建一个继承自Thread类的子类。
    • 在子类中重写run方法,将线程的执行逻辑写在run方法中。
    • 创建该子类的实例,并调用start方法启动线程。

实现Runnable接口

  • 结构

    • 通过实现Runnable接口并将其传递给Thread类来创建线程。
  • 步骤

    • 创建一个实现Runnable接口的类。
    • 在类中实现run方法,将线程的执行逻辑写在run方法中。
    • 创建该类的实例,并将其作为参数传递给Thread对象。
    • 调用Thread对象的start方法启动线程。

。。。

总结

  • 继承Thread类:简单直接,但不支持多继承。
  • 实现Runnable接口:推荐使用,符合Java单继承多实现的特性。
  • 使用Callable和Future:适用于需要返回结果或抛出异常的任务。
  • 使用ExecutorService框架:适用于需要高效管理线程池的场景。
4、创建线程池呢、每个参数的意义
5、通过那几种方式保证线程安全
6、jvm加载
7、了解数据库事物?特性?
8、怎么提高sql查询性能 (只说了添加索引,分库分表)
  • 优化查询语句

    • 避免SELECT *,尽量只查询需要的列
    • 使用WHERE条件筛选数据,减少返回的数据量
    • 避免在WHERE子句中使用函数,使用函数会导致无法使用索引,从而降低查询性能。
  • 索引优化

    • 创建合适的索引
    • 使用覆盖索引
  • 数据库分区

    • 使用分区表:将大表按照某个字段(如日期、ID范围)进行分区,减少单个分区的数据量,提高查询性能。
  • 数据库配置优化

    • 调整数据库配置:根据实际需求调整数据库的内存分配、缓存大小、连接数等配置参数,提高整体性能。
9、String特性是什么

不可变性(Immutability)

  • 在Java中,String对象是不可变的。一旦创建,字符串的值就不能更改。如果需要修改字符串,则会创建一个新的字符串对象。

字符串池(String Pool)

  • Java使用字符串池来优化字符串的存储和管理。当你创建一个字符串字面量时,JVM会先检查字符串池中是否存在相同的字符串如果存在,则返回对该字符串的引用;如果不存在,则在池中创建新的字符串

字符串连接(Concatenation):

  • Java支持使用+操作符进行字符串连接,也可以使用StringBuilder或StringBuffer来提高性能。StringBuilder和StringBuffer是可变的,并且提供了对字符串的高效修改操作。
10、redis数据类型
11、redis持久化 答了(AOF,RDB)接着问了他们之间的区别

面经整理二

作者:MO小天才
链接:https://www.nowcoder.com/feed/main/detail/363997511497459ea21b12aa686439d7?sourceSSR=search
来源:牛客网

1、spring是怎么实现aop的
  • 一种用于分离关注点的技术,特别是在横切关注点(如日志记录、事务管理、权限控制等)方面。Spring AOP的实现主要基于代理模式。

  • 切面(Aspect)

    • 面是横切关注点的模块化表现,是通知(advice)和切入点(pointcut)的结合
  • 通知(Advice)

    • 通知是在切入点上执行的操作常见的通知类型包括前置通知(before)、后置通知(after)、返回通知(after returning)、异常通知(after throwing)和环绕通知(around)。
  • 切入点(Pointcut)

    • 切入点定义了通知应当应用到哪些连接点(Join Points)。通常使用AspectJ表达式语言来定义切入点。
  • 目标对象(Target Object)

    • 目标对象是被通知的对象,即那些包含核心业务逻辑的方法被AOP框架拦截的对象
  • 代理(Proxy)

    • 代理是AOP框架创建的对象,它被用来代替目标对象代理对象负责拦截方法调用,并在适当的时间执行通知
  • 织入(Weaving)

    • 织入是将切面应用到目标对象并创建代理对象的过程。Spring AOP在运行时通过动态代理或CGLIB代理进行织入。
2、aop的原理
  • Spring AOP通过动态代理(JDK动态代理和CGLIB代理)实现了AOP的功能使得我们可以在不修改业务代码的情况下将横切关注点(如日志记录、事务管理等)应用到目标对象的方法上
3、用户通过客户端或者浏览器发送请求,在springboot框架下是如何接收这个请求、解析并向下透传到control层的

1、接收请求

  • 当用户发送HTTP请求时,嵌入式服务器会受到请求

2、请求解析

  • 将请求传递给Servlet容器进行解析,变成HttpServletRequest和HttpServletResponse对象

3、拦截请求

  • DispatcherServlet,它是Spring MVC的前端控制器,负责处理所有进来的HTTP请求。
  • 映射到所有路径(/),因此它会拦截所有请求

4、映射控制器

  • 会根据请求的URL和HTTP方法(GET、POST等),通过HandlerMapping找到相应的处理器
  • HandlerMapping的工作是将请求映射到具体的控制器类和方法上。

5、调用控制器方法

  • DispatcherServlet会使用HandlerAdapter调用控制器方法
    • 控制器方法通常使用@RequestMapping或其他映射注解(如@GetMapping、@PostMapping等)来指定URL路径和请求方法

6、处理请求并返回响应对象

  • 控制器方法处理请求,并返回一个响应对象,一般是调用service层的处理业务逻辑,并将结果返回

7、返回给客户端

  • 响应返回给Servlet容器,Servlet容器将响应发送回客户端
4、mysql的底层结构
5、索引分为哪几个类型
6、以非聚簇索引作为一个查询条件,去获取到整条记录的中间过程是什么

1. 在非聚簇索引中查找键值

  • 查找索引键:、
    • 数据库引擎在非聚簇索引的 B+ 树中查找符合查询条件的索引键
  • 获取聚簇索引键
    • 找到匹配的索引键后,获取指向实际数据记录的指针或聚簇索引键值

2. 在聚簇索引中查找完整记录

  • 查找数据记录
    • 使用从非聚簇索引中获取的聚簇索引键值,在聚簇索引的 B+ 树中查找完整的数据记录。
  • 返回完整记录
    • 找到对应的叶节点后,提取并返回完整的数据记录
7、建索引要满足哪些原则
8、hashmap扩容的过程

触发条件

  • 容量(capacity):HashMap桶(bucket)数组的当前大小。
  • 负载因子(load factor):当HashMap的元素数量超过capacity * load factor时触发扩容。默认负载因子为0.75。

扩容过程

  • a. 计算新容量

    • HashMap扩容时,新容量通常是旧容量的两倍。扩容后,新容量和新阈值会重新计算。
  • b. 创建新桶数组

    • 创建一个大小为新容量的新的桶数组
  • c.重新分配元素

    • 将旧桶数组中的所有元素重新计算哈希并分配到新桶数组中。由于容量的变化,元素的位置可能会发生变化。
    • 链表节点重新分配旧桶数组中存在链表时,需要对链表节点重新分配。根据节点的哈希值决定其在新桶数组中的位置。如果节点的哈希值与旧容量进行按位与运算结果为0,则其放置在新桶中的原位置,否则放置在原位置加上旧容量的位置。
  • 更新HashMap的引用和阈值

    • 将HashMap的桶数组引用更新为新的桶数组,并更新阈值。
9、synchronized和可重入锁有哪些区别
10、线程安全的集合concurrenthashmap是如何保证线程安全的
  • 分段锁
    • 减少锁争用,提高并发性能。
  • CAS 操作和自旋锁
    • 保证原子性和线程安全。
  • 细粒度锁
    • 对每个桶进行锁定,允许更多并发操作。
  • 树化和链化
    • 提高哈希冲突处理效率,每一个桶的链表长度超过阈值,转为红黑树,提高查找和出入效率
  • 无锁读操作
    • 提高并发读性能。
  • 高效扩容
    • 分批次进行扩容,减少性能影响。
11、java的内存分布
  • 堆(Heap):存储所有对象实例和数组,分为年轻代和老年代。
  • 栈(Stack):每个线程都有自己的栈,存储局部变量、方法调用等信息
  • 方法区(Method Area):存储类的元数据、静态变量、常量池等。在Java 8之后称为元空间(Metaspace)。
  • 程序计数器(PC Register):指示当前线程执行的字节码位置。
  • 本地方法栈(Native Method Stack):为虚拟机执行本地方法服务。
12、1.8的jvm默认的两个垃圾回收器是哪两个,区别是什么
  • 1. Parallel GC(并行垃圾回收器)

    • 特点
      • 年轻代收集:使用多线程的复制算法(copying)
      • 老年代收集:使用多线程的标记-压缩算法(mark-compact)
      • 多线程:使用多个线程同时进行垃圾回收操作,适用于多核 CPU,提高垃圾回收效率
      • 吞吐量优先:Parallel GC 设计的目标是最大化吞吐量,最小化垃圾回收对应用程序的影响时间
  • 2. G1 GC(Garbage-First Garbage Collector)

    • 特点
      • 分区:将整个堆内存划分为多个相等大小的独立区域(Region),每个区域可以充当 Eden、Survivor 或 Old 区
      • 混合收集年轻代和老年代一起进行收集(mixed collection),在一次垃圾回收过程中,既回收年轻代,又回收部分老年代
      • 并发标记G1 GC 使用并发标记阶段来标记存活对象,从而减少应用程序暂停时间。
      • 停顿时间目标:允许用户指定期望的停顿时间,通过调优停顿时间目标来满足应用程序的低延迟要求。
13、有一个web服务的接口,刚上线的时候没有什么问题,突然一段时间后客户端调用该接口,该接口的反馈都是超时,如何定位这个服务的问题
  • 1. 检查服务器资源
  • 2. 检查应用日志
  • 3. 检查数据库性能
    • 慢查询
    • 连接池耗尽
    • 锁争用
  • 4、检查外部依赖是否正常
    • 缓存服务器
    • 消息队列
  • 5、分析网络问题
    • 网络延迟
    • 防火墙和负载均衡器
  • 6、重现问题
    • 尝试在本地或者测试环境中,重现则个问题,以便更容易调试和分析

正式面试

第一面
A面
  • 1、重点介绍一下个人项目

    • 说的过于琐碎,没有必要,需要概括一下,重点说出你的要点,而不是很细致地完全讲出来,没有必要!
    • 重点介绍Java相关的项目
  • 2、浮点数了解吗?怎么实现的

    • 浮点数的实现主要是基于科学计数法,有以下四部分构成,分别是
      • 符号位:0正数,1负数
      • 基数:使用二进制表示
      • 指数:表示基数应该乘以多少次幂,可以是正数或者负数
      • 尾数:有效位数
    • 特殊
      • 不能表示所有数字,涉及小数比较时,需要处理小数误差
      • 正零和负零
      • 无穷大:超出表示范围的数字
      • NaN:未定义或者不确定地结果
  • 3、给你一个数组,数组里面全部是数字,然后再给你一个s表示窗口的大小,从最左侧滑动,然后滑动到最右侧,求取每一次移动的滑动窗口平均值,你计算一下滑动窗口的最小值?并计算一下的时间复杂度和空间复杂度

    • 想不出更好的做法,只能使用模拟的方式实现,维护滑动窗口的sum,然后每一次计算一次平均值,比较平均值的最最优值。
    • 时间复杂度是O(n),空间复杂度是O(1).
B面
  • 1、简单的自我介绍

    • 项目介绍太过繁琐,很多细节不需要,只需要说你做了什么项目,大概概括一下!项目就说做了什么,然后你有哪些工作,然后总结一下,没有必要面面俱到,什么都说。
  • 项目上线了吗?

    • 并没有上线,在等进一步审核。
  • 系统的准确率是多少

    • 分情况说,比较真实。
  • 针对这种情况有什么其他的优化方案吗?

    • 拓宽信息模态
    • 更换信息收集场景
  • 这个项目是基于大语言模型的,谁在维护和训练?

    • 使用开源大语言模型的API直接调用的,并没有的自己训练一个大语言模型
  • 说一下ThreadLocal的使用?怎么防止内存泄露

    • ThreadLocal是的key是弱引用,但是他的value会强引用,通过调用对应的set等方法会自动回收不再使用value,但是线程不再被使用,不再调用对应方法就不会进行内存回收,导致内存泄漏
    • 如何避免内存泄漏
      • 先获取到 ThreadLocalMap 这个引用的,并且调用了它的 remove 方法,手动调用remove方法,防止内存泄漏
  • MySQL中聚簇索引和非聚簇索引有什么区别

    • 聚簇索引

      • 聚簇索引决定了磁盘上的存储顺序,同时聚簇索引的叶子节点包含了完整的数据行,查询聚簇索引无需额外查询数据
      • 主键默认创建为聚簇索引,如果没有指定主键,会选择一个唯一非空索引作为聚簇缩影。
    • 非聚簇索引

      • 非聚簇索引是单独的索引结构,叶子节点不包含数据行,而是包含了指向数据行的指针
      • 非聚簇索引和数据的存储顺序无关,非聚簇索引的叶子节存储的是数据行的位置或者主键位置,通常需要二次查找。
  • 建表的时候,没有指定任何列作为他的主键,会创建的主键索引吗?

    • 首先,检查表中是否存在唯一非空的索引,有就将其作为主键索引
    • 然后,如果表中没有主键,没有唯一索引,自动生成一个6字节长的隐藏主键列,不可见无法访问
  • InnoDB引擎默认的隔离级别是什么?这个隔离级别会带来问题?做了哪些操作来尽量缓解这个问题?

    • 可重复读,解决了脏读和不可重读,但是还是存在部分幻读
    • 如何解决幻读的问题
      • 提供了两种查询方式的,分别是快照读和当前读,都会产生幻读
      • 针对快照读,使用MVCC来解决幻读问题,第一次查询生成一个readview,然后在当前事务中都使用相同的readview,保证结果相同。
      • 针对当前读,依靠行级锁中的间隙锁来实现
      • 但并不能完全避免,一般是没有加上对应的for update
  • SpringAOP的实现过程

    • 用于在不修改代码的情况下,动态地将某些行为应用到特定的方法或者类上。主要是基于动态代理和字节码操作实现。
    • 定义一个切面类,这个切面类中要指明增强的方式是@Before还是@AfterReturning等,同时指定对应地切点,然后定义具体的需要额外执行的逻辑和行为。
    • 主要是定义通知类和配置类,具体编程实现如下

在这里插入图片描述

  • 第二阶段会有一个算法题,HR会通知你的。
ThreadLocal了解吗?如何防止内存泄漏?

资料来源
ThreadLocal介绍

  • 应用场景
    • ThreadLocal用作保存每一个线程独享的对象,每一个线程都创建一个副本,这样每一个线程都可以修改自己所拥有的副本,不会影响其他线程的副本,确保线程安全
      • 保存线程不安全的工具类,典型需要使用的类是SimpleDataFormat
    • ThreadLocal 用作每一个线程内需要独立保存信息,以便供线程内其他方法更方便地获取该信息场景。线程内每个方法获取到的信息是不一样的,前面执行的方法保存了信息后,后续方法可以通过ThreadLocal获取,避免传参,类似线程内的全局变量。
    • 保存业务的一些内容,比如说在拦截器中获取用户的信息,可以让不同方法直接使用,避免了传递参数麻烦

在这里插入图片描述

ThreadLocal可以用来解决共享资源的多线程访问的问题吗?

  • 不是,ThreadLocal 并不是用来解决共享资源问题的。虽然 ThreadLocal 确实可以用于解决多线程情况下的线程安全问题,但其资源并不是共享的,而是每个线程独享的

ThreadLocal和Synchronized关系?

  • ThreadLocal 是通过让每个线程独享自己的副本,避免了资源的竞争。
  • synchronized 主要用于临界资源的分配,在同一时刻限制最多只有一个线程能访问该资源。

ThreadLocal、Thread和ThreadLocalMap的关系

  • 一个Thread有一个ThreadLocalMap,而ThreadLocalMap的key就是一个一个ThreadLocal

防止内存泄漏

  • 内存泄漏
    • 当某一个对象不在有用时,占用的内存却不能被回收,是内存泄漏
  • 引用分析
    • ThreadLocal中的key是弱引用,如果不在引用了,垃圾回收机制能够成功收回
    • ThreadLocal中value是强引用,如果某一个Thread长时间运行,并且某一个Thread不再被使用,那么这个value就会内存泄漏,没法被垃圾回收
      • set、remove和rehash都会刷新key-value,如果key为null,会自动回收对应的value,但是如果不调用就没有办法刷新了
  • 如何避免内存泄漏
    • 先获取到 ThreadLocalMap 这个引用的,并且调用了它的 remove 方法,手动调用remove方法,防止内存泄漏
如何对复杂对象进行深拷贝?
  • 实现 Cloneable 接口并重写 clone() 方法
    • 通过实现 Cloneable 接口并重写 clone() 方法,可以对对象进行深拷贝
  • 使用序列化进行深拷贝
    • 通过将对象序列化为字节流然后反序列化,可以实现深拷贝。
  • 递归实现深拷贝
    • 通过自定义的递归方法,我们可以实现对复杂对象的深拷贝。此方法适用于对象嵌套结构较为复杂的情况。
SpringAOP的实现过程
  • 一种用于分离关注点的技术,特别是在横切关注点(如日志记录、事务管理、权限控制等)方面。Spring AOP的实现主要基于代理模式。

  • 切面(Aspect)

    • 面是横切关注点的模块化表现,是通知(advice)和切入点(pointcut)的结合
  • 通知(Advice)

    • 通知是在切入点上执行的操作常见的通知类型包括前置通知(before)、后置通知(after)、返回通知(after returning)、异常通知(after throwing)和环绕通知(around)。
  • 切入点(Pointcut)

    • 切入点定义了通知应当应用到哪些连接点(Join Points)。通常使用AspectJ表达式语言来定义切入点。
  • 目标对象(Target Object)

    • 目标对象是被通知的对象,即那些包含核心业务逻辑的方法被AOP框架拦截的对象
  • 代理(Proxy)

    • 代理是AOP框架创建的对象,它被用来代替目标对象代理对象负责拦截方法调用,并在适当的时间执行通知
  • 织入(Weaving)

    • 织入是将切面应用到目标对象并创建代理对象的过程。Spring AOP在运行时通过动态代理或CGLIB代理进行织入。
  • Spring AOP通过动态代理(JDK动态代理和CGLIB代理)实现了AOP的功能使得我们可以在不修改业务代码的情况下将横切关注点(如日志记录、事务管理等)应用到目标对象的方法上

笔试

对于必胜的理解

  • 对于序列a而言,其中的元素[a1,a2,a3,a4,a5]等,要是必赢的情况下,随便取出来一个数字ax,使得剩下元素的最大值amax和amin的累加和 大于等于 target,但是最大值不能大于等于target,只要能够是这种情况,那么先手肯定是必胜的。
  • 如果是这种只能够报数三次的情况,肯定能够判定出来的。当前方选什么才能让后方必输
  • 但是如果当前报数并不能立刻判定出能否获胜的话,就不好判定了!

A和B都会按照最优的方式报数

  • 如果轮到A,只要A能够赢,或者说存在必赢的方案,一定会选择必赢的方案
  • 如果轮到B,只要B能够赢,或者说存在必赢的方案,一定会选择必赢的方案
  • 言外之意,就是A每一次做出决定之前,都要判定会不会给B带来必赢的局面,如果能够给B带来必赢的局面,就不选当前方案

能否通过动态规划实现

  • 如果使用动态规划实现,必须能够使用集合的语言进行表达,但是这个题目不知道怎么用集合的语言表达。
  • 我应该还是会使用回溯实现!

回溯条件

  • 如果无论A选什么,B都存在必胜的条件,那么就返回false
  • 如果无论A选了某个分支,B无论选了什么,那么就返回true

具体实现代码

import java.io.FilterOutputStream;
import java.util.*;

/**
 * @author Long Guo
 * @create 2024-08-10-14:32
 *///TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or
// click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.
public class Main {
    // 定义不同的状态表示当前是谁在报数
    static boolean A = true;
    static boolean B = false;
    static List<Integer> list;   // 能够报的数字的列表
    static Map<Integer, Boolean> cached;

    static boolean dfs(int target, boolean AorB, int cacheNum) {
        /*
         * 具体含义:当前做选择的游戏玩家是否存在胜利的情况,存在返回true,不存在返回false
         * list表示剩余列表中所有能够选择的数字
         * target表示目标数值
         * AorB表示对应的角色,true表示为A先手,false表示B,后手
         * 基本思路:
         *    在所有搜索树中,总共有两种选择关系,分别是的由A到B和由B到A
         *        A选B:一旦所有B的情况中,有一种是B必胜的情况,那么就不能选,因为B一定会选必胜的情况,所以这里需要的将所有B可选的情况通过与&进行连接
         *        B选A:一旦所有的A的情况中,有一种的A必胜的情况,B就不会选,所以这里要选择全部是false的情况,也就是通过或进行连接,全部为false的情况
         *    最终通过回溯,判定当前节点下是否存在A必胜的情况
         */

        // 临界条件,必赢状况,这里需要特殊处理,如果是B的回合,那就是A必输的情况
        int m = list.size();
        if (list.get(m - 1) >= target) return true;

        // 分情况遍历所有可能地选择
        boolean flag;
        for (int i = 0; i < m; i++) {
            int curNum = cacheNum | (1 << list.get(i));
            if (cached.containsKey(curNum)) flag = cached.get(curNum);
            else {
                int tempNum = list.get(i);
                int tempTar = target - tempNum;
                list.remove(i);
                flag = dfs(tempTar, !AorB, curNum);
                cached.put(curNum, flag);
                list.add(i, tempNum);
            }
            if (!flag) return true;
        }
        return false;
    }

    static boolean isAlwaysWin(int N, int Target) {
        for (int i = 0; i < N; i++) {
            int cacheNum = 0 | (1 << i + 1);
            int tempNum = list.get(i);
            int tempTar = Target - tempNum;
            list.remove(i);
            if (!dfs(tempTar, B, cacheNum)) return true;
            list.add(i, tempNum);
            cached.put(cacheNum, false);
        }
        return false;
    }
//

    public static void main(String[] args) {

        // 处理输入输出
//        Scanner in = new Scanner(System.in);
//        String nInput = in.nextLine();
//        String targetInput = in.nextLine();
//        int n = Integer.parseInt(nInput.replaceAll("[^0-9]]",""));
//        int target = Integer.parseInt(targetInput.replaceAll("[^0-9]]",""));
        int n = 5;
        int target = 8;

        // 生成对应的可报数的列表
        list = new ArrayList<>();
        cached = new HashMap<>();
        for (int i = 1; i <= n; i++) list.add(i);

        // 这两种是一个特殊情况,刚好是需要顺次报完所有的数字的,偶数的话后手必胜,奇数的话A必胜
        if (n % 2 == 0 && target == (n + 1) * n / 2) System.out.println(false);
        else if (n % 2 == 1 && target == (n + 1) * n / 2) System.out.println(true);
        else
            // 正常需要迭代判断的情况
            System.out.println(isAlwaysWin(n, target));

        //
//        System.out.println(isAlwaysWinSingle(list,n,target));

    }
}

总结

  • 过不过再说哈,现在先写在这里!
  • 第一面还行,直接让我过了,说过两天给我发一道算法题,然后让我好好做一下!继续在准备,晚上去运动一下,然后接着看项目!加油!
    8/11
  • 今天晚上完成了wind数据的笔试,差不多花了四五个小时,然后想清楚了,也写完了。感觉还行,还能继续面试!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2216278.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java基础(5)继承与多态

目录 ​编辑 1.前言 2.正文 2.1继承 2.1.1继承概念 2.1.2继承语法 2.1.3子类访问父类 2.1.4super关键字 2.2多态 2.2.1多态概念 2.2.2多态条件 2.2.3重写 2.2.4向上转型与向下转型 2.2.5为什么要使用多态 3.小结 1.前言 哈喽大家好啊&#xff0c;今天继续来为大…

汽车开发流程管理工具赋能安全与质量

随着数字化、人工智能、自动化系统及物联网技术的迅速发展&#xff0c;工程驱动型企业正面临重大转型挑战&#xff0c;亟需加速并深化其变革步伐。众多企业正试图通过采用基于模型的系统工程(MBSE)、产品线工程(PLE)、ASPICE、安全、网络安全、软件定义汽车、敏捷和精益开发实践…

微信小程序上传组件封装uploadHelper2.0使用整理

一、uploadHelper2.0使用步骤说明 uploadHelper.js ---上传代码封装库 cos-wx-sdk-v5.min.js---腾讯云&#xff0c;对象存储封装库 第一步&#xff0c;下载组件代码&#xff0c;放置到自己的小程序项目中 第二步、 创建上传对象&#xff0c;执行选择图片/视频 var _this th…

【java Web如何开发?】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

讯飞与腾讯云:Android 实时语音识别服务对比选择

在 移动端 接入实时语音识别方面&#xff0c;讯飞和腾讯云都是优秀的选择&#xff0c;但各有其特点和优势。以下是对两者的详细比较&#xff1a; 一、讯飞语音识别 1.1 讯飞实时语音识别介绍 1.1.1 功能特点 1.支持多种语言识别&#xff0c;满足不同语种用户的需求。(普通话/…

Kafka之消费者组与消费者

消费者&#xff08;Consumer&#xff09;在Kafka的体系结构中是用来负责订阅Kafka中的主题&#xff08;Topic&#xff09;&#xff0c;并从订阅的主题中拉取消息后进行处理。 与其他消息中间件不同&#xff0c;Kafka引入一个逻辑概念——消费组&#xff08;Consumer Group&…

使用excel.js(layui-excel)进行layui多级表头导出,根据单元格内容设置背景颜色,并将导出函数添加到toolbar

本段是菜狗子的碎碎念&#xff0c;解决办法请直接从第二段开始看。layui多级表头的导出&#xff0c;弄了两天才搞定&#xff0c;中途一度想放弃&#xff0c;还好坚持下来了。一开始用的是layui的toolbar里自带的那个导出&#xff0c;但是多级表头没有正常导出&#xff0c;单元格…

FPGA学习(6)-基础语法参数化设计阻塞与非阻塞

目录 1.两种参数化不改变源文件&#xff0c;只改仿真文件的值 2.参数化设计实现模块的重用 2.1不用参数化方法 2.1.1源文件 2.1.2仿真文件 2.1.3仿真波形及实验 2.2 用参数方法 2.2.1调用之前写的led灯闪烁模块&#xff0c;在本源函数中&#xff0c;例化4次调用之前的模…

【pyspark学习从入门到精通7】DataFrames_2

目录 创建 DataFrames 生成我们自己的 JSON 数据 创建 DataFrame 创建临时表 简单的 DataFrame 查询 DataFrame API 查询 SQL 查询 创建 DataFrames 通常&#xff0c;您会通过使用 SparkSession&#xff08;或在 PySpark shell 中调用 spark&#xff09;导入数据来创建 …

SpinalHDL之错误集(一)

本文作为SpinalHDL学习笔记第七十六篇&#xff0c;作为错误集使用&#xff0c;类似高中生的错题集&#xff0c;记录使用SpinalHDL过程中遇到的问题&#xff0c;小到语法错误、版本兼容问题&#xff0c;大到SpinalHDL库函数错误等等&#xff0c;持续更新。 SpinalHDL学习笔记总…

记录 ruoyi-vue-plus在linux 部署遇到的问题

整理 linux 文件不要放在 /, 根目录下&#xff0c;要放在 home 文件夹下。docker 启动mysql 容器&#xff0c;映射的 my.cnf 文件不能设置太高权限&#xff0c;权限太高有安全问题&#xff0c;无法读取。 linux 使用注意事项 docker 文件夹 部署在home文件夹下 总结学习到的…

Asp.Net Core 发布 IIS、docker、Azure、文件夹、AAS、ASF、AWM等

发布 微软资料 微软资料 在 IIS 工作进程 (w3wp.exe) 内托管 ASP.NET Core 应用&#xff0c;称为进程内托管模型。 将 Web 请求转发到运行 Kestrel 服务器的后端 ASP.NET Core 应用&#xff0c;称为进程外托管模型。 发布到IIS 》》》Asp.net 之前 》》》 Asp.net Core …

JavaScript 网页设计案例:使用 Canvas 实现趣味打气球小游戏

JavaScript 网页设计案例&#xff1a;使用 Canvas 实现趣味打气球小游戏 在网页设计中&#xff0c;交互性和趣味性是吸引用户的重要因素。借助 JavaScript 和 HTML5 的 canvas 元素&#xff0c;我们可以轻松实现各种动画效果&#xff0c;今天将带你打造一个有趣的 打气球小游戏…

Vxe vue vxe-table 分享实现打印表格以及同时打印两张表

Vxe vue vxe-table 分享实现打印表格以及同时打印两张表 vxe-table 默认情况下支持单表打印。 在有些情况下&#xff0c;页面上同时有几张表&#xff0c;这时需要一次性打印出来。可以利用 Vxe 自带的分页打印功能&#xff0c;实现多张表同时打印。 效果 点击打印后自动调起预…

Redis --- 第四讲 --- 常用数据结构 --- set、zset

一、set类型的基本介绍 谈到一个术语&#xff0c;这个术语很可能有多种含义。Set一个含义是集合&#xff0c;一个含义是设置。 集合就是把一些有关联数据放到一起。 1、集合中的元素是无序的&#xff01; 2、集合中的元素是不能重复的。 和list类似&#xff0c;集合中的每…

数据治理为何如此简单?

欢迎来文末免费获取数据治理相关PPT和文档 引言 随着大数据技术的迅速发展&#xff0c;企业积累的数据量呈现爆炸式增长。有效的数据管理已经成为企业提高决策效率、增强竞争优势的重要手段。在这样的背景下&#xff0c;数据治理逐渐成为企业数据管理中不可或缺的一环。它不仅…

15分钟学Go 第1天:Go语言简介与特点

Go语言简介与特点 1. Go语言概述 Go语言&#xff08;又称Golang&#xff09;是由谷歌于2007年开发并在2009年正式发布的一种开源编程语言。它旨在简单、高效地进行软件开发&#xff0c;尤其适合于网络编程和分布式系统。 1.1 发展背景 多核处理器&#xff1a;随着计算机硬件…

MFC扩展库BCGControlBar Pro v35.1新版亮点:改进网格控件性能

BCGControlBar库拥有500多个经过全面设计、测试和充分记录的MFC扩展类。 我们的组件可以轻松地集成到您的应用程序中&#xff0c;并为您节省数百个开发和调试时间。 BCGControlBar专业版 v35.1已全新发布了&#xff0c;这个版本改进网格控件的性能、增强工具栏编辑器功能等。 …

hadoop集群搭建-克隆虚拟机,安装jdk,hadoop

2.2 hadoop运行环境的搭建 2.2.1 环境准备 1&#xff09;安装模板虚拟机&#xff0c;IP地址 192.168.10.100&#xff0c;主机名hadoop100&#xff0c;内存41GB&#xff0c;硬盘50GB 2&#xff09;虚拟机配置 首先测试虚拟机是否可以正常上网&#xff0c;测试方法ping www.b…

HarmonyOS Next模拟器异常问题及解决方法

1、问题1&#xff1a;Failed to get the device apiVersion. 解决方法&#xff1a;关闭模拟器清除用户数据重启