天鹏恒宇面试

快速排序和冒泡排序的时间复杂度

冒泡排序(Bubble Sort):

  • 最坏时间复杂度: O(n^2) – 在数组完全逆序的情况下,每次比较和交换都会发生。
  • 平均时间复杂度: O(n^2) – 对于任何情况,平均时间复杂度都是 O(n^2)。
  • 最好时间复杂度: O(n) – 当数组已经有序时,只需要进行一次遍历。

快速排序(Quick Sort):

  • 最坏时间复杂度: O(n^2) – 当每次选择的基准元素都是当前子数组中的最大或最小元素时。
  • 平均时间复杂度: O(n log n) – 在平均情况下,快速排序的性能较好。
  • 最好时间复杂度: O(n log n) – 当每次选择的基准元素都能平均地将数组分成两半时。

快速排序和冒泡排序的优缺点

  1. 算法思想:
    • 冒泡排序:通过重复遍历待排序的元素,比较相邻元素,并在不符合顺序的情况下交换它们,直到整个数组有序。
    • 快速排序:使用分治法的思想,选择一个基准元素,将数组分为两个子数组,使得左边的元素都小于基准,右边的元素都大于基准,然后递归地对子数组进行排序。
  2. 性能:
    • 冒泡排序的平均和最坏时间复杂度都是O(n^2),因此不适用于大规模数据的排序。
    • 快速排序的平均时间复杂度为O(n log n),在实践中通常比冒泡排序更快。但最坏情况下可能达到O(n^2),取决于选择的基准元素。
  3. 稳定性:
    • 冒泡排序是稳定的,相等元素的相对位置不会改变。
    • 快速排序在一般情况下是不稳定的,因为在交换过程中相等元素的相对位置可能会改变。
  4. 空间复杂度:
    • 冒泡排序是原地排序算法,只需要常数级别的额外空间。
    • 快速排序在递归实现时需要额外的栈空间,因此空间复杂度较高。
  5. 适用场景:
    • 冒泡排序适用于小型数据集,或者在其他排序算法不适用的特殊情况。
    • 快速排序适用于大型数据集,是常用的高效排序算法之一。

什么是链表,什么是线性表

线性表:

  1. 定义: 线性表是一种数据结构,其中元素排列成一条线,具有唯一的首元素和唯一的尾元素。线性表中的元素之间存在直接关系,即每个元素都有一个前驱元素和一个后继元素,除了首元素没有前驱,尾元素没有后继。
  2. 实现: 线性表可以通过数组或链表来实现。数组是一块连续的内存空间,元素的存储位置是相邻的;链表是一种非连续的数据结构,元素通过指针相连。
  3. 存储特性: 线性表的元素在内存中是按线性顺序存储的,可以通过索引(或位置)来访问元素。

链表:

  1. 定义: 链表是一种线性表的实现方式,其中元素的存储位置不一定是相邻的,而是通过指针相连的。每个元素都包含一个数据项和一个指向下一个元素的指针。
  2. 结构: 链表包括单链表、双链表和循环链表等。在单链表中,每个节点有一个指向下一个节点的指针;在双链表中,每个节点有一个指向前一个节点和一个指向下一个节点的指针;在循环链表中,最后一个节点指向第一个节点,形成一个环。
  3. 灵活性: 由于链表不要求内存空间连续,插入和删除元素相对容易,不需要移动其他元素。这使得链表在某些操作上比数组更灵活。
  4. 缺点: 与数组相比,链表的随机访问速度较慢,因为必须通过指针一个节点一个节点地遍历。同时,链表需要额外的存储空间来存储指针。

查询、插入、删除数据,哪个表的效率高

  1. 线性表:
    • 线性表是一种按照线性顺序存储数据的数据结构,数组是一种常见的线性表实现。在线性表中,元素在内存中是相邻存储的,因此通过索引可以快速访问元素。对于查询来说,线性表的查询操作是O(1)的时间复杂度,即常数时间。
    • 插入和删除操作涉及到元素的移动,特别是在数组中插入或删除元素时,需要移动后续元素,平均时间复杂度为O(n),其中n是元素的个数。
  2. 链表:
    • 链表是一种非连续存储的数据结构,元素通过指针相互连接。在链表中,查询操作相对较慢,因为需要从头节点开始逐个遍历找到目标元素,平均时间复杂度为O(n)。
    • 插入和删除操作在链表中比较高效,特别是在双向链表中。在链表中插入或删除元素时,只需要调整相邻元素的指针,平均时间复杂度为O(1)。

综合来看,如果主要操作是查询,并且数据规模较大,线性表的效率可能更高。如果主要操作是插入和删除,并且需要频繁地进行这些操作,链表可能更适合。

MySQL的时间函数知道哪些

  1. NOW():

    • 返回当前日期和时间的值,包括年、月、日、小时、分钟和秒。
    SELECT NOW();
    
  2. CURDATE():

    • 返回当前日期的值,不包括时间。
    SELECT CURDATE();
    
  3. CURTIME():

    • 返回当前时间的值,不包括日期。
    SELECT CURTIME();
    
  4. DATE():

    • 从日期时间值中提取日期部分。
    SELECT DATE(NOW());
    
  5. TIME():

    • 从日期时间值中提取时间部分。
    SELECT TIME(NOW());
    
  6. YEAR():

    • 从日期或日期时间值中提取年份。
    SELECT YEAR(NOW());
    
  7. MONTH():

    • 从日期或日期时间值中提取月份。
    SELECT MONTH(NOW());
    
    
  8. DAY():

    • 从日期或日期时间值中提取日。
    SELECT DAY(NOW());
    
    
  9. HOUR():

    • 从时间或日期时间值中提取小时。
    SELECT HOUR(NOW());
    
    
  10. MINUTE():

    • 从时间或日期时间值中提取分钟。
    SELECT MINUTE(NOW());
    
    
  11. SECOND():

    • 从时间或日期时间值中提取秒。
    SELECT SECOND(NOW());
    
    
  12. DATEDIFF():

    • 返回两个日期之间的天数差。
    SELECT DATEDIFF('2023-01-01', '2022-01-01');
    
    
  13. DATE_ADD():

    • 在日期或日期时间上添加一个时间间隔。
    SELECT DATE_ADD(NOW(), INTERVAL 1 DAY);
    
    
  14. DATE_SUB():

    • 从日期或日期时间中减去一个时间间隔。
    SELECT DATE_SUB(NOW(), INTERVAL 1 WEEK);
    

MySQL的存储过程

MySQL 存储过程是一组预先编译的 SQL 语句,可以在 MySQL 数据库中保存和重复使用。存储过程可以包含 SQL 语句、控制结构(例如条件和循环)、变量、参数和错误处理等元素。通过使用存储过程,可以将复杂的业务逻辑封装在数据库中,提高代码的可维护性和执行效率。

以下是 MySQL 存储过程的基本结构:

DELIMITER //

CREATE PROCEDURE procedure_name (parameter_list)
BEGIN
    -- SQL statements
END //

DELIMITER ;
  • DELIMITER 用于更改 SQL 语句的结束标志,以便在存储过程中使用分号 (;)。在定义存储过程时,需要用 // 作为结束标志,而在存储过程内部的 SQL 语句结束时,可以使用普通的分号。
  • CREATE PROCEDURE 用于创建存储过程。
  • procedure_name 是存储过程的名称。
  • parameter_list 是存储过程的参数列表,包括参数的名称和数据类型。
  • BEGIN...END 之间是存储过程的主体,包含了一系列 SQL 语句和控制结构。
  • // 用于结束存储过程的定义。
  • DELIMITER ; 用于恢复 SQL 语句的结束标志为分号。

百万量级的数据需要进行连表查询,可能出现数据断层,如何解决,让数据量变小

  1. 使用索引:
    • 确保参与联表查询的列都有索引,这有助于加速查询过程。在 MySQL 中,可以使用 CREATE INDEX 语句创建索引。
  2. 分页查询:
    • 将大查询拆分成多个小查询,每次只查询一部分数据,这可以通过分页来实现。在很多情况下,用户不需要一次性看到全部的数据,分页查询可以提供更好的用户体验。
  3. 使用合适的字段:
    • 只查询需要的字段,而不是选择全部字段。这可以减小传输的数据量,提高查询性能。
    • (只认可了这个)
  4. 使用合适的数据类型:
    • 使用较小的数据类型来存储数据,以减小存储空间和提高查询性能。
  5. 缓存查询结果:
    • 如果查询的数据不经常变化,可以考虑使用缓存技术,将查询结果缓存起来,避免每次都执行查询操作。
  6. 分库分表:
    • 考虑将数据按照某种规则分散到多个数据库或者多个表中,以减小单个查询的数据量。
  7. 使用数据库优化工具:
    • 使用数据库的性能分析工具,如MySQL的EXPLAIN语句,来分析查询语句的执行计划,以便优化查询性能。
  8. 数据压缩:
    • 对于需要传输的大量数据,可以考虑使用数据压缩技术,减小传输的数据量。
  9. 使用合适的连接方式:
    • 根据查询的需求选择合适的连接方式,如 INNER JOIN、LEFT JOIN 等。不同的连接方式对性能有不同的影响。
  10. 数据库服务器优化:
    • 确保数据库服务器的硬件和配置足够支持大数据量的查询,例如增加内存、优化磁盘读写速度等。

webappi接口的协议

  1. HTTP/HTTPS:
    • 绝大多数 Web API 使用 HTTP(Hypertext Transfer Protocol)或其加密版本 HTTPS 来进行通信。HTTP是一种无状态的协议,通过请求-响应的方式进行通信。RESTful API(Representational State Transfer)是一种基于 HTTP 协议的常见设计风格,它使用 HTTP 方法(GET、POST、PUT、DELETE等)对资源进行操作。
  2. SOAP(Simple Object Access Protocol):
    • SOAP 是一种基于 XML 的协议,用于在计算机网络上交换结构化的信息。它定义了一种通信的框架,允许在不同的操作系统和编程语言之间进行通信。相对于 REST,SOAP 更为庞大,支持更多的功能,但也因此更为复杂。
  3. WebSocket:(可算可不算)
    • WebSocket 是一种在单个 TCP 连接上提供全双工通信的协议。与 HTTP 不同,WebSocket 允许在客户端和服务器之间建立持久连接,实时推送数据。这使得它适用于需要实时性的应用,如即时通讯和实时数据更新。

TCP协议四次挥手

  1. 第一次挥手(Client -> Server):
    • 客户端发送一个带有 FIN(Finish)标志的TCP报文段,表示它已经完成数据的发送。
  2. 第二次挥手(Server -> Client):
    • 服务器接收到客户端的 FIN 报文段,会发送一个 ACK(Acknowledgment)报文段,表示已经收到了客户端的关闭请求。
  3. 第三次挥手(Server -> Client):
    • 服务器发送一个带有 FIN 标志的TCP报文段,表示服务器已经完成数据的发送。
  4. 第四次挥手(Client -> Server):
    • 客户端接收到服务器的 FIN 报文段,会发送一个 ACK 报文段,表示已经收到了服务器的关闭请求。

接口前端调用为什么会产生跨域

  1. 协议不同:
    • 当前网页使用的协议(http或https)与请求的资源使用的协议不同,就会发生跨域。例如,一个页面使用https协议,但请求一个使用http协议的接口。
  2. 域名不同:
    • 当前网页的域名与请求的资源的域名不同,就会发生跨域。例如,一个页面在www.example.com域下,但请求了api.example-api.com域下的接口。
  3. 端口不同:
    • 当前网页的端口与请求的资源的端口不同,也会发生跨域。例如,一个页面在www.example.com:8080域下,但请求了www.example.com:3000域下的接口。
  4. 子域名不同:
    • 即使是不同的子域名,也会被认为是跨域。例如,一个页面在app.example.com域下,但请求了api.example.com域下的接口。

输出字符串“兰州文理学院”中的“文理学院”有几种方式

  1. 字符串截取:

    • 使用substring方法可以截取字符串的指定部分。
    String originalString = "兰州文理学院";
    String targetString = originalString.substring(2); // 从索引为2的位置开始截取,得到"文理学院"
    System.out.println(targetString);
    
  2. 正则表达式匹配:

    • 使用正则表达式来匹配目标字符串。
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    public class Main {
        public static void main(String[] args) {
            String originalString = "兰州文理学院";
            String regex = "文理学院";
            
            Pattern pattern = Pattern.compile(regex);
            Matcher matcher = pattern.matcher(originalString);
            
            if (matcher.find()) {
                String targetString = matcher.group();
                System.out.println(targetString);
            }
        }
    }
    
  3. 字符串查找:

    • 使用indexOf方法查找目标字符串在原始字符串中的位置。
    String originalString = "兰州文理学院";
    int index = originalString.indexOf("文理学院");
    
    if (index != -1) {
        String targetString = originalString.substring(index);
        System.out.println(targetString);
    }
    
  4. 使用 split 方法:

    String originalString = "兰州文理学院";
    String[] parts = originalString.split("文理学院");
    
    if (parts.length > 1) {
        String targetString = parts[1];
        System.out.println(targetString);
    }
    
  5. 将字符串转换为字符数组:

    String originalString = "兰州文理学院";
    char[] arr = originalString.toCharArray();
    for(int i = 2; i <= 5; i ++){
        System.out.print(arr[i]);
    }
    

Was this helpful?

0 / 0

发表回复 0

Your email address will not be published.