服务端开发之Java备战秋招面试3

news2024/12/24 21:04:03

今天继续学习,先做两题算法题练练手,在继续整理八股文,深入理解,才能在面试的时候有更好地表现,一起加油吧,希望秋招多拿几个令人心动的offer,冲吧。

目录

1、算法题:判断链表中是否有环

2、算法题:合并二叉树

3.什么是跳表?

4.Spring的特性?

5.mysql事务特性?mysql隔离级别?mysql怎么实现可重复读的呢?

6.讲一下B树,B+树,哈希表,AVL树,红黑树?

7.怎么保证HashMap的线程安全?

8. CAS(Compare And Swap) 、synchronized、volatile?

9.ThreadLocal是否可保证资源的同步?它会导致内存泄漏?

10.jvm 垃圾回收是什么时候触发?

11.线程池有哪几种类型?

12.TCP三次握手四次挥手?

13.OSI七层和TCP/IP四层?OSI五层?

14.算法题:两个有序链表合并?

15.算法题:反转链表


1、算法题:判断链表中是否有环

题目链接:判断链表中是否有环_牛客题霸_牛客网

判断链表是否有环,用快慢指针即可,快指针每次走两步,慢指针每次走一步,如果慢指针不为空,快慢指针能相遇,则链表有环,否则,链表无环。

注意:边界值的处理,防止空指针异常。

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public boolean hasCycle(ListNode head) {
        if(head == null || head.next == null){
            return false ;
        }
        ListNode fast = head;
        ListNode slow = head ;
        while(fast != null && fast.next != null){
            fast = fast.next.next ;
            slow = slow.next ;
            if(slow == fast){
                return true ;
            }
        }
        return false ;
    }
}

2、算法题:合并二叉树

可以使用递归法和迭代法合并,递归法如下,递归合并到树t1上。

import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 * }
 */

public class Solution {
    /**
     * 
     * @param t1 TreeNode类 
     * @param t2 TreeNode类 
     * @return TreeNode类
     */
    public TreeNode mergeTrees (TreeNode t1, TreeNode t2) {
        // write code here
        //合并到t1上
        if(t1 == null && t2 == null){
            return null ;
        }
        if(t1 == null){
            return t2 ;
        }
        if(t2 == null){
            return t1 ;
        }
        t1.val = t1.val + t2.val ;
        t1.left = mergeTrees(t1.left,t2.left) ;
        t1.right = mergeTrees(t1.right,t2.right) ;
        return t1 ;
    }
}

迭代法如下:

建立一个队列,层次遍历的方式,累加相应的节点值。

import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 * }
 */

public class Solution {
    /**
     * 
     * @param t1 TreeNode类 
     * @param t2 TreeNode类 
     * @return TreeNode类
     */
    public TreeNode mergeTrees (TreeNode t1, TreeNode t2) {
        // write code here
        //合并到t1上
      if(t1 == null && t2 == null){
        return null ;
      }
      if(t1 == null){
        return t2 ;
      }
      if(t2 == null){
        return t1 ;
      }
      Queue<TreeNode> queue = new LinkedList() ;
      queue.offer(t1) ;
      queue.offer(t2) ;
      while(!queue.isEmpty()){
        TreeNode node1 = queue.poll() ;
        TreeNode node2 = queue.poll() ;
        node1.val = node1.val + node2.val ;
        if(node1.left != null && node2.left != null){
            queue.offer(node1.left) ;
            queue.offer(node2.left) ;
        }
        if(node1.right != null && node2.right != null){
            queue.offer(node1.right) ;
            queue.offer(node2.right) ;
        }
        if(node1.left == null && node2.left != null){
            node1.left = node2.left ;
        }
        if(node1.right == null && node2.right != null){
            node1.right = node2.right ;
        }
      }
      return t1 ;
    }
}

3.什么是跳表?

1)跳表,又叫做跳跃表、跳跃列表,在有序链表的基础上增加了“跳跃”的功能。
2)跳表在原来的有序链表上加上了多级索引,通过索引来快速查找;可以支持快速的删除、插入和查找操作。
3)跳表实际上是一种增加了前向指针的链表,是一种随机化的数据结构。
4)Redis中 的 SortedSet、LevelDB 中的 MemTable 都用到了跳表。
5)对比平衡树, 跳表的实现和维护会更加简单, 跳表的搜索、删除、添加的平均时间复杂度是 O(logn)。
参考这篇博客:跳表(Skip List)_wink22的博客-CSDN博客_跳表

4.Spring的特性?

三大特性:依赖注入(DI),控制反转(IOC),面向切面编程(AOP).

可以参考这篇博客:【Spring篇】Spring的三大特性_我是不贪嘴吖的博客-CSDN博客_spring特性

5.mysql事务特性?mysql隔离级别?mysql怎么实现可重复读的呢?

ACID:原子性,一致性,隔离性,持久性

读未提交,读已提交,可重复读,串行化。

可重复读是Mysql的默认隔离级别,就是指在同一事务中多次读取的数据是一致的。

实现方法是 Mysql通过多版本并发控制(MVCC):我们常说的MVCC是由MySQL数据库InnoDB存储引擎实现的,并非是由MySQL本身实现的,不同的存储引擎,对MVCC都有不同的实现。就是在InnoDB引擎中,InnoDB在每行记录后面保存两个隐藏的列,分别保存了这个行的创建时间(版本号)和行的删除时间(版本号)。这里存储的并不是实际的时间值,而是系统版本号,当数据被修改时,版本号加1。在读取事务开始时,系统会给当前读事务一个版本号,然后,事务会读取版本号<=当前版本号的数据。此时如果其他写事务修改了这条数据(增删改),那么这条数据的版本号就会加1,从而比当前事务的版本号高,所以,当前事务读取的并不是更新后的数据,而是当前事务对应版本下的数据。
参考链接:mysql 可重复读的实现原理_Vance.的博客-CSDN博客_mysql可重复读实现原理

6.讲一下B树,B+树,哈希表,AVL树,红黑树?

这2篇介绍了红黑树,B树,B+树,讲的还可以:为什么要使用红黑树,B树和B+树_-停泊的博客-CSDN博客_索引 为什么用红黑树

B树、B+树、红黑树_prefect_start的博客-CSDN博客_b树 b+树 红黑树

这篇文章看完了,写的比较全面:面试题

7.怎么保证HashMap的线程安全?

通过ConcurrentHashMap线程安全类实现:JDK1.7通过对segment加锁,片段锁。JDK1.8降低了锁的粒度,通过对头结点加锁来保证线程安全的。

看完理论这篇博客,讲的还可以:ConcurrentHashMap是如何保证线程安全的?_Tom弹架构的博客-CSDN博客

8. CAS(Compare And Swap) 、synchronized、volatile?

1、 synchronized 是悲观锁,属于抢占式,会引起其他线程阻塞。

2、 volatile 提供多线程共享变量可见性和禁止指令重排序优化。

3、 CAS 是基于冲突检测的乐观锁(非阻塞)。

参考这篇,写的很好:基础篇:详解锁原理,synchronized、volatile+cas底层实现 - 知乎

9.ThreadLocal是否可保证资源的同步?它会导致内存泄漏?

  • 当使用ThreadLocal声明变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本
  • 从上面的概念可知,ThreadLocal其实并不能保证变量的同步性,只是给每一个线程分配一个变量副本
  • hreadLocalMap 是使用 ThreadLocal 的弱引用作为 Key 的,弱引用的对象在 GC 时会被回收。ThreadLocalMap使用ThreadLocal的弱引用作为key,如果一个ThreadLocal没有外部强引用来引用它,那么系统 GC 的时候,这个ThreadLocal势必会被回收,这样一来,ThreadLocalMap中就会出现key为null的Entry,就没有办法访问这些key为null的Entry的value,如果当前线程再迟迟不结束的话,这些key为null的Entry的value就会一直存在一条强引用链:Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value永远无法回收,造成内存泄漏。
  • 每次使用完ThreadLocal,都调用它的remove()方法,清除数据,防止内存泄漏。

参考这篇博文:ThreadLocal使用注意:线程不安全,可能会发生内存泄漏_深山猿的博客-CSDN博客_threadlocal有什么隐患

10.jvm 垃圾回收是什么时候触发?

参考这篇博客:jvm :垃圾回收是什么时候触发? 垃圾回收算法? 有哪些垃圾回收器?_花和尚也有春天的博客-CSDN博客

11.线程池有哪几种类型?

1、newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理所需,可灵活回收空闲线程,若线程数不够,则新建线程。

2、newFixedThreadPool:创建一个固定大小的线程池,即指定线程数的线程。可控制并发的线程数量,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中。

3、newSingleThreadExecutor:创建一个单线程的线程池,即只创建唯一的工作者线程来执行任务,,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

4、newScheduleThreadPool:创建一个定长的线程池,支持定时及周期性任务执行。  

推荐通过 new ThreadPoolExecutor() 的写法创建线程池,这样写线程数量更灵活开发中多数用这个类创建线程。

12.TCP三次握手四次挥手?

TCP的三次握手和四次挥手实质就是TCP通信的连接和断开。

三次握手:为了对每次发送的数据量进行跟踪与协商,确保数据段的发送和接收同步,根据所接收到的数据量而确认数据发送、接收完毕后何时撤消联系,并建立虚连接。

四次挥手:即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。

三次握手过程详细说明:

1、客户端发送建立TCP连接的请求报文,其中报文中包含seq序列号,是由发送端随机生成的,并且将报文中的SYN字段置为1,表示需要建立TCP连接。(SYN=1,seq=x,x为随机生成数值);

2、服务端回复客户端发送的TCP连接请求报文,其中包含seq序列号,是由回复端随机生成的,并且将SYN置为1,而且会产生ACK字段,ACK字段数值是在客户端发送过来的序列号seq的基础上加1进行回复,以便客户端收到信息时,知晓自己的TCP建立请求已得到验证。(SYN=1,ACK=x+1,seq=y,y为随机生成数值)这里的ack加1可以理解为是确认和谁建立连接;

3、客户端收到服务端发送的TCP建立验证请求后,会使自己的序列号加1表示,并且再次回复ACK验证请求,在服务端发过来的seq上加1进行回复。(SYN=1,ACK=y+1,seq=x+1)。
 

四次挥手​​​​​​​过程详细说明:

1、客户端发送断开TCP连接请求的报文,其中报文中包含seq序列号,是由发送端随机生成的,并且还将报文中的FIN字段置为1,表示需要断开TCP连接。(FIN=1,seq=x,x由客户端随机生成);

2、服务端会回复客户端发送的TCP断开请求报文,其包含seq序列号,是由回复端随机生成的,而且会产生ACK字段,ACK字段数值是在客户端发过来的seq序列号基础上加1进行回复,以便客户端收到信息时,知晓自己的TCP断开请求已经得到验证。(FIN=1,ACK=x+1,seq=y,y由服务端随机生成);

3、服务端在回复完客户端的TCP断开请求后,不会马上进行TCP连接的断开,服务端会先确保断开前,所有传输到A的数据是否已经传输完毕,一旦确认传输数据完毕,就会将回复报文的FIN字段置1,并且产生随机seq序列号。(FIN=1,ACK=x+1,seq=z,z由服务端随机生成);

4、客户端收到服务端的TCP断开请求后,会回复服务端的断开请求,包含随机生成的seq字段和ACK字段,ACK字段会在服务端的TCP断开请求的seq基础上加1,从而完成服务端请求的验证回复。(FIN=1,ACK=z+1,seq=h,h为客户端随机生成)
至此TCP断开的4次挥手过程完毕。
参考这篇博客:一文搞懂TCP的三次握手和四次挥手_不脱发的程序猿的博客-CSDN博客_三次握手和四次挥手

注意:TCP两次握手行不行?

因为TCP协议是双向的,第三次握手是为了使得sever知道客户答应了连接的请求。其中两次握手只能确定从客户端到服务端的网络是可达的,但却无法保证从服务端到客户端的网络是可达的。所以我们一定要保证双向的可达。

还有一个重要的原因:seq(序号)的初始化,要互相确定两方互相开始发送的序号,便于之后的发送、控制、纠错等等。

假如我们使用两次握手,则我们可以设想这么一种情况:客户向服务器进行请求,服务器同意并分配资源,向客户也发送信息,但此时这条信息因为网络原因丢失,客户便不了解服务器收没收到它发出的信息,则客户会继续向服务器发出请求,服务器若接收到,会认为是别的机器进行请求,继续分配资源,且也依然无法建立从服务器到客户的连接。
 

13.OSI七层和TCP/IP四层?OSI五层?

看下面一个图就可以大概了解了,如下:应用层、表示层、会话层可以归为应用层,数据链路层和物理层可以归结为网络接口层。

参照这篇博客:OSI七层和TCP/IP四层、五层协议 - 一切随风

14.算法题:两个有序链表合并?

思路1:迭代法,定义一个头节点为0的,依次遍历合并即可,最后再把头节点去掉。

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode Merge(ListNode list1,ListNode list2) {
        //迭代法
        if(list1 == null){
            return list2 ;
        }
        if(list2 == null){
            return list1  ;
        }
        ListNode pHead = new ListNode(0) ;
        ListNode cur = pHead ;
        while(list1 != null && list2 != null){
            if(list1.val <= list2.val){
                cur.next = list1 ;
                list1 = list1.next ;
            }else{
                cur.next = list2 ;
                list2 = list2.next ;
            }
            cur = cur.next ;
        }
        //哪个链表还未结束,接在后面
        cur.next = list1 != null ? list1 : list2 ;
        //去掉头节点的0
        return pHead.next ;
        
    }
}

思路2:递归法。递归合并。

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode Merge(ListNode list1,ListNode list2) {
        //递归法
        if(list1 == null){
            return list2 ;
        }
        if(list2 == null){
            return list1  ;
        }
        //若list1的值更小,则递归合并后接到list1上
        if(list1.val <= list2.val){
            list1.next = Merge(list1.next,list2) ;
            return list1 ;
        }else{//反之,递归合并接到list2上
            list2.next = Merge(list1,list2.next) ;
            return list2 ;
        }
        
    }
}

15.算法题:反转链表

题目链接:反转链表_牛客题霸_牛客网

思路1:在遍历链表时,将当前节点的next 指针改为指向前一个节点。由于节点没有引用其前一个节点,因此必须事先存储其前一个节点。在更改引用之前,还需要存储后一个节点。最后返回新的头引用。

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode ReverseList(ListNode head) {
        ListNode pre = null ;
        while(head != null){
            //先定义下一个指针,防止被覆盖
            ListNode head_next = head.next ;
            //让当前元素指向pre
            head.next = pre ;
            //更新pre
            pre = head ;
            //更新当前元素
            head = head_next ;
        }
        return pre ;
    }
}

递归法:每次递归反转两个,如下:

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode ReverseList(ListNode head) {
      //递归法
      if(head == null || head.next == null){
        return head ;
      }
      ListNode ans = ReverseList(head.next) ;
      head.next.next = head ;
      head.next = null ;
      return ans ;

    }
}

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

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

相关文章

带你了解IP报警柱的特点

IP可视报警柱是一款室外防水紧急求助可视对讲终端。安装在学校、广场、道路人流密集和案件高发区域&#xff0c;当发生紧急情况或需要咨询求助时按下呼叫按钮立即可与监控中心值班人员通话&#xff0c;值班人员也可通过前置摄像头了解现场情况并广播喊话。IP可视报警柱的使用特…

【双重注意机制:肺癌:超分】

Dual attention mechanism network for lung cancer images super-resolution &#xff08;肺癌图像超分辨率的双重注意机制网络&#xff09; 目前&#xff0c;肺癌的发病率和死亡率均居世界恶性肿瘤之首。提高肺部薄层CT的分辨率对于肺癌筛查的早期诊断尤为重要。针对超分辨…

收割不易,五面Alibaba终拿Java岗offer

前言 前段时间有幸被阿里的一位同学内推&#xff0c;参加了阿里巴巴Java岗位的面试&#xff0c;本人19年双非本科软件工程专业&#xff0c;目前有一年半的工作经验&#xff0c;面试前就职于一家外包公司。如果在自己本人拿到offer之前&#xff0c;如果有人告诉我一年工作经验可…

会声会影2023专业版视频处理制作软件功能详细介绍

会声会影是一款专业的视频处理和制作软件&#xff0c;也是目前影楼制作结婚和一般视频特效制作的必备软件&#xff0c;他是一款专为个人及家庭所设计的数码影片编辑软件&#xff0c;可将数 字或模拟摄像机所拍下来的如成长写真、国外旅游、个人MTV、生日派对、毕业典礼等精彩生…

C++ 修改程序进程的优先级(Linux,Windows)

文章目录1、Linux1.1 常用命令1.1.1 不占用终端运行和后台运行方式1.1.2 查询进程1.1.3 结束进程1.1.4 优先级命令1.2 C 代码示例1.2.1 代码一1.2.2 代码二2、Windows2.1 简介2.2 函数声明2.3 C 代码示例2.3.1 代码一2.3.2 代码二结语1、Linux 1.1 常用命令 1.1.1 不占用终端…

关于死锁的一些基本知识

目录 死锁是什么&#xff1f; 死锁的三种经典情况 1.一个线程&#xff0c;一把锁&#xff0c;连续加锁两次&#xff0c;如果锁是不可重入锁就会死锁。 不可重入锁与可重入锁&#xff1a; 2.两个线程两把锁&#xff0c;t1和t2各自针对于锁A和锁B加锁&#xff0c;再尝试获取…

Redis 集群

文章目录一、集群简介二、Redis集群结构设计&#x1f349;2.1 数据存储设计&#x1f349;2.2 内部通信设计三、cluster 集群结构搭建&#x1f353;3-1 cluster配置 .conf&#x1f353;3-2 cluster 节点操作命令&#x1f353;3-3 redis-trib 命令&#x1f353;3-4 搭建 3主3从结…

用ChatGPT生成Excel公式,太方便了

ChatGPT 自去年 11 月 30 日 OpenAI 重磅推出以来&#xff0c;这款 AI 聊天机器人迅速成为 AI 界的「当红炸子鸡」。一经发布&#xff0c;不少网友更是痴迷到通宵熬夜和它对话聊天&#xff0c;就为了探究 ChatGPT 的应用天花板在哪里&#xff0c;经过试探不少人发现&#xff0c…

同步和非同步整流DC/DC转换区别

在DC/DC转换器中&#xff0c;非隔离式降压开关稳压器包括两种拓扑结构&#xff1a;非同步整流&#xff08;二极管&#xff09;型和同步整流型。非同步整流型已经使用多年&#xff0c;具有简单的开关稳压器电路&#xff0c;效率勉强超过80%。随后&#xff0c;电池供电应用&#…

VMware 的网络适配器 桥接-NAT-仅主机

大家使用VMware安装镜像之后&#xff0c;是不是都会考虑虚拟机的镜像系统怎么连上网的&#xff0c;它的连接方式是什么&#xff0c;它ip是什么&#xff1f; 路由器、交换机和网卡 1.路由器 一般有几个功能&#xff0c;第一个是网关、第二个是扩展有线网络端口、第三个是WiFi功…

Redis 被问麻了...

Redis是面试中绕不过的槛&#xff0c;只要在简历中写了用过Redis&#xff0c;肯定逃不过。今天我们就来模拟一下面试官在Redis这个话题上是如何一步一步深入&#xff0c;全面考察候选人对于Redis的掌握情况。 小张&#xff1a; 面试官&#xff0c;你好。我是来参加面试的。 …

Hadoop-MapReduce

Hadoop-MapReduce 文章目录Hadoop-MapReduce1 MapRedcue的介绍1.1 MapReduce定义1.2 MapReduce的思想1.3MapReduce优点1.4MapReduce的缺点1.5 MapReduce进程1.6 MapReduce-WordCount1.6.1 job的讲解2 Hadoop序列化2.1 序列化的定义2.2 hadoop序列化和java序列化的区别3 MapRedu…

RabbitMQ发布确认模式

目录 一、发布确认原理 二、发布确认的策略 &#xff08;一&#xff09;开启发布确认的方法 &#xff08;二&#xff09;单个确认模式 &#xff08;三&#xff09;批量确认模式 &#xff08;四&#xff09;异步确认模式 &#xff08;五&#xff09;如何处理异步未确认消…

华为CT6100双千M路由记录

该文章仅仅记录使用CT6100的流程&#xff0c;不提供任何参考和建议。 一、简介 设备&#xff1a;华为CT6100瘦客服端&#xff0c;J1800cpu&#xff0c;不包含外壳&#xff0c;有双千M网口&#xff0c;2G内存8G硬盘。系统&#xff1a;esir的高大全openwrt版本用途&#xff1a;对…

QT 完美实现圆形按钮

QT 版本&#xff1a;5.6.0 官方的按钮有些普通&#xff0c;如果我们想要换成自己喜欢的按钮而却无从下手&#xff0c;那么请继续往下阅读&#xff08;皮一下&#xff09;。 首先&#xff0c;可以在网络上搜索一下自己喜欢的按钮图形&#xff08;或者可以自行绘制&#xff09;…

十大算法基础——上(共有20道例题,大多数为简单题)

一、枚举&#xff08;Enumerate&#xff09;算法 定义&#xff1a;就是一个个举例出来&#xff0c;然后看看符不符合条件。 举例&#xff1a;一个数组中的数互不相同&#xff0c;求其中和为0的数对的个数。 for (int i 0; i < n; i)for (int j 0; j < i; j)if (a[i] …

偏向锁、轻量级锁、自旋锁、重量级锁,它们都是什么?有什么关联

互斥锁的本质是共享资源。 当有多个线程同时对一个资源进行操作时&#xff0c;为了线程安全&#xff0c;要对资源加锁。 更多基础内容参看上文《深入了解Java线程锁(一)》 接下来&#xff0c;我们来看看两个线程抢占重量级锁的情形&#xff1a; 上图讲述了两个线程ThreadA和…

SMART PLC斜坡函数功能块(梯形图代码)

斜坡函数Ramp的具体应用可以参看下面的文章链接: PID优化系列之给定值斜坡函数(PLC代码+Simulink仿真测试)_RXXW_Dor的博客-CSDN博客很多变频器里的工艺PID,都有"PID给定值变化时间"这个参数,这里的给定值变化时间我们可以利用斜坡函数实现,当然也可以利用PT1…

vb.net 视频音频转换

视频&音频转换工具 V23.0主流视频音频转换工具&#xff0c;Kbps数值越大&#xff0c;音频品质越高&#xff08;前提原视频或音频文件品质高&#xff09;。.NETFramework V4.0点击按钮 选中文件 保存文件 即可转换&#xff0c;转换速度较快&#xff0c;转换后的音频文件未发…

Detr源码解读(mmdetection)

Detr源码解读(mmdetection) 1、原理简要介绍 整体流程&#xff1a; 在给定一张输入图像后&#xff0c;1&#xff09;特征向量提取&#xff1a; 首先经过ResNet提取图像的最后一层特征图F。注意此处仅仅用了一层特征图&#xff0c;是因为后续计算复杂度原因&#xff0c;另外&am…