JAVA八股文面经问题整理第9弹

文章目录

提问问题

  1. 笔试题:给定一个不重复的整数数组构建最大二叉树
  2. 笔试题:给一个字符串 s ,反转字符串中 单词 的顺序
  3. 什么是强缓存和协商缓存?
  4. HTTPS与HTTP的区别?
  5. HTTP多个TCP连接怎么实现?
  6. DNS是什么,及其查询过程?
  7. 解释⼀下⽤户态和核⼼态?
  8. 解释⼀下⻚⾯置换算法,例如LRU(最近最少使⽤)、FIFO(先进先出)等?
  9. 说⼀说你了解的MVCC机制
  10. MySQL什么使⽤B+树来作索引,它的优势什么?
  11. 索引失效的场景有哪些?

问题1

在数组中 找最大值的节点作为当前节点,用最大值的index切割左右子树的区间,往复循环到数组元素为0,代码如下;更详细思路可以参考之前的文章最大二叉树

class Solution {
    public TreeNode constructMaximumBinaryTree(int[] nums) {
        return constructMaximumBinaryTree1(nums, 0, nums.length);
    }
 
    public TreeNode constructMaximumBinaryTree1(int[] nums, int leftIndex, int rightIndex) {
        if (rightIndex - leftIndex < 1) {// 遍历完数组时返回空
            return null;
        }
 
        if (rightIndex - leftIndex == 1) {// 只有一个元素
            return new TreeNode(nums[leftIndex]);
        }
 
        int maxIndex = leftIndex;// 最大值所在位置
        int maxVal = nums[maxIndex];// 最大值
        for (int i = leftIndex + 1; i < rightIndex; i++) {//遍历找最大值和节点位置
            if (nums[i] > maxVal){
                maxVal = nums[i];
                maxIndex = i;
            }
        }
 
        TreeNode root = new TreeNode(maxVal);//最大值作为当前节点
 
        // 根据maxIndex划分左右子树
        root.left = constructMaximumBinaryTree1(nums, leftIndex, maxIndex);
        root.right = constructMaximumBinaryTree1(nums, maxIndex + 1, rightIndex);
 
        return root;
    }
}

问题2

用辅助数组, 去掉空格后,一个个单词从后往前遍历然后放入,代码如下;更详细思路可以参考之前的文章翻转字符串中的单词

class Solution {
   /**
     * 不使用Java内置方法实现
     */
    public String reverseWords(String s) {
      
        // 1.去除首尾以及中间多余空格
        StringBuilder sb = removeSpace(s);
        // 2.反转整个字符串
        reverseString(sb, 0, sb.length() - 1);
        // 3.反转各个单词
        reverseEachWord(sb);
 
        return sb.toString();
    }
 
    private StringBuilder removeSpace(String s) {// 去除首尾以及中间多余空格
 
        int start = 0;
        int end = s.length() - 1;
 
        while (s.charAt(start) == ' ') start++;
        while (s.charAt(end) == ' ') end--;
 
        StringBuilder sb = new StringBuilder();
        while (start <= end) {
            char c = s.charAt(start);
            if (c != ' ' || sb.charAt(sb.length() - 1) != ' ') {//遇到连续的空格就跳过
                sb.append(c);
            }
            start++;
        }
 
        return sb;//返回处理好的字符串
    }
 
     //反转区间[start, end]里的字符
    public void reverseString(StringBuilder sb, int start, int end) {
        while (start < end) {
            char temp = sb.charAt(start);
            sb.setCharAt(start, sb.charAt(end));
            sb.setCharAt(end, temp);
            start++;
            end--;
        }
    }
 
 
    private void reverseEachWord(StringBuilder sb) {//反转各个单词
        int start = 0;
        int end = 1;
        int n = sb.length();
        while (start < n) {
            while (end < n && sb.charAt(end) != ' ') {//判断各个单词
                end++;
            }
            reverseString(sb, start, end - 1);//反转单词
            start = end + 1;
            end = start + 1;
        }
    }
}


问题3

强缓存(Strong Caching)和协商缓存(Negotiation Caching)是HTTP缓存机制中的两种策略,它们用于减少网络延迟和服务器负载,提高网页加载速度。强缓存减少了对服务器的请求次数,而协商缓存确保了即使在资源更新后,用户也能及时获得新内容

强缓存是指当浏览器请求一个资源时,如果该资源在本地缓存中有可用的副本,并且没有过期,浏览器将直接使用这个副本而无需再次从服务器请求

强缓存主要依赖于HTTP头部中的两个字段:ExpiresCache-Control

  • Expires是一个HTTP头部字段,它提供一个日期/时间,告诉浏览器在这个时间之前资源是新鲜的,可以直接使用本地缓存的版本。然而,Expires是基于服务器时间的,如果客户端和服务器之间存在时间差异,可能会导致缓存提前失效。

  • Cache-Control提供了更多的控制选项,如max-age(指定资源在缓存中有效的最大时间长度)、no-cache(每次使用前都必须验证)、public(任何缓存都可以存储资源)和private(仅客户端缓存可以存储资源)等。

.协商缓存发生在资源已经过期但强缓存失败时。此时,浏览器会发送一个条件性请求到服务器,该请求包含一个验证令牌,通常是If-Modified-Since(基于Last-Modified时间戳)或If-None-Match(基于ETag值)。服务器接收到请求后,会比较资源的当前版本和客户端提供的验证令牌

  • 如果资源自上次请求以来没有变化,服务器会返回一个304 Not Modified状态码,浏览器则会继续使用本地缓存的副本。
  • 如果资源已更改,服务器会返回200 OK状态码和最新的资源内容,浏览器随后会用新内容替换本地缓存的旧副本。


问题4

HTTP和HTTPS的区别

  1. HTTP 是明⽂传输,⽽HTTPS 通过 SSL\TLS 进⾏了加密
  2. HTTP 的端⼝号是 80,HTTPS 是 443
  3. HTTPS 需要到 CA 申请证书
  4. HTTP 的连接简单,是⽆状态的;HTTPS 协议是由 SSL+HTTP 协议构建的可进⾏加密传输、身份认证的⽹络协议,⽐ HTTP 协议安全


问题5

多个tcp连接靠某些服务器对 Connection: keep-alive 的 Header 进⾏了⽀持

简⽽⾔之,完成这个 HTTP 请求之后,不要断开 HTTP 请求使⽤的 TCP 连接。这样的好处是连接可以被重新使⽤,之后发送 HTTP 请求的时候不需要重新建⽴ TCP 连接,以及如果维持连接,那么 SSL 的开销也可以避免


问题6

DNS(Domain Name System)域名管理系统,是当⽤户使⽤浏览器访问⽹址之后,使⽤的第⼀个重要协议。DNS 要解决的是域名和 IP 地址的映射问题

查询过程
1. ⾸先⽤户在浏览器输⼊URL地址后,会先查询浏览器缓存是否有该域名对应的IP地址。


2. 如果浏览器缓存中没有,会去计算机本地的Host⽂件中查询是否有对应的缓存。


3. 如果Host⽂件中也没有则会向本地的DNS解析器(通常由你的互联⽹服务提供商(ISP)提供)
发送⼀个DNS查询请求。


4. 如果本地DNS解析器没有缓存该域名的解析记录,它会向根DNS服务器发出查询请求。根DNS服务器并不负责解析域名,但它能告诉本地DNS解析器应该向哪个顶级域(.com/.net/.org)的
DNS服务器继续查询。


5. 本地DNS解析器接着向指定的顶级域DNS服务器发出查询请求。顶级域DNS服务器也不负责具体的域名解析,但它能告诉本地DNS解析器应该前往哪个权威DNS服务器查询下⼀步的信息。


6. 本地DNS解析器最后向权威DNS服务器发送查询请求。 权威DNS服务器是负责存储特定域名和IP地址映射的服务器。当权威DNS服务器收到查询请求时,它会查找"example.com"域名对应的IP地址,并将结果返回给本地DNS解析器


7. 本地DNS解析器将收到的IP地址返回给浏览器,并且还会将域名解析结果缓存在本地,以便下次访问时更快地响应。


问题7

⽤户态 User Mode 和核⼼态 Kernel Mode ,是操作系统中两种不同的执⾏模式,⽤于控制进程
或程序对计算机硬件资源的访问权限和操作范围

⽤户态:在⽤户态下,进程或程序只能访问受限的资源和执⾏受限的指令集,不能直接访问操作系统的核⼼部分,也不能直接访问硬件资源,⽤户态下的 CPU 不允许独占,也就是说 CPU 能够被其他程序获取。


核⼼态:核⼼态是操作系统的特权级别允许进程或程序执⾏特权指令和访问操作系统的核⼼部
。在核⼼态下,进程可以直接访问硬件资源,执⾏系统调⽤,管理内存、⽂件系统等操作。处
于内核态的 CPU 可以从⼀个程序切换到另外⼀个程序,并且占⽤ CPU 不会发⽣抢占情况,⼀
般处于特权级 0 的状态我们称之为内核态


问题8

假设⼿机内存有限,只能同时运⾏四个手机应用。当想切换到⼀个新的应用时,需要从内存中换出⼀个旧的应用,以便为新的应用腾出空间。不同的⻚⾯置换算法就相当于不同的切换策略,例如:

LRU(最近最少使⽤)算法:每次选择最⻓时间没有被使⽤的应用进⾏切换

这种策略基于你对应用的喜好,认为最近被使⽤过的应用很可能还会被使⽤,⽽最久未被使⽤的应用很可能不会再被使⽤。LRU算法可以有效地减少切换次数,但是实现起来⽐较复杂,需要记录每个应用的使⽤时间或者维护⼀个使⽤顺序的列表。


FIFO(先进先出)算法:每次选择最早进⼊内存的应用进⾏切换

这种策略很简单,只需要维护⼀个应用队列,每次淘汰队⾸的应用,然后把新的应用加⼊队尾。但是FIFO算法可能会淘汰⼀些经常被使⽤的应用,导致切换次数增加。⽽且FIFO算法有可能出现⻉拉迪异常(Beladyanomaly),即当分配给内存的空间增加时,切换次数反⽽增加

常⻅⻚⾯置换算法有最佳置换算法(OPT)、最近最久未使⽤算法(LRU)、时钟算法(Clock)

1. 最佳置换算法: 该算法根据未来的⻚⾯访问情况,选择最⻓时间内不会被访问到的⻚⾯进⾏置
。这种算法只是⼀种理想情况下的置换算法,通常是⽆法实现的

2. 最近最久未使⽤算法:LRU算法基于⻚⾯的使⽤历史,通过选择最⻓时间未被使⽤的⻚⾯进⾏置换

LRU算法的核⼼思想是,最近被访问的⻚⾯可能在未来被再次访问,⽽最⻓时间未被访问的
⻚⾯可能是最不常⽤的,因此将其置换出去可以腾出空间给新的⻚⾯
。LRU算法通常是使⽤⼀个数据结构去维护⻚⾯的使⽤历史,维护使⽤历史就是通过访问字段实现的。访问字段的位数和操作系统分配给该进程的⻚⾯数有关,⽐如分配4个⻚⾯,访问字段就是2位,16个⻚⾯,访问字段就是4位,依次类推。如此,每⼀个⻚⾯的访问字段都可以不同,通过访问字段的不同,我们就可以判断⻚⾯的使⽤历史。


3. 时钟算法:Clock算法基于⼀个环形链表或者循环队列数据结构来管理⻚⾯的访问情况,

⽤于选择被置换的⻚⾯

Clock算法的核⼼思想是通过使⽤⼀个指针(称为时钟指针)在环形链表上遍历,检查⻚⾯是否被访问过。这个访问过同样需要我们上⾯说到的访问字段来表示,此时访问字段只有⼀位。每个⻚⾯都与⼀个访问位相关联,标记该⻚⾯是否被访问过。当需要进⾏⻚⾯置换时,Clock算法从时钟指针的位置开始遍历环形链表。 如果当前⻚⾯的访问位为0,表示该⻚⾯最久未被访问,可以选择进⾏置换。将访问位设置为1,继续遍历下⼀个⻚⾯。 如果当前⻚⾯的访问位为1,表示该⻚⾯最近被访问过,它仍然处于活跃状态。将访问位设置为0,并继续遍历下⼀个⻚⾯如果遍历过程中找到⼀个访问位为0的⻚⾯,那么选择该⻚⾯进⾏置换。


问题9

MVCC(Multi-Version Concurrency Control)多版本并发控制,⽤于管理多个事务同时访问和修改数据库的数据,⽽不会导致数据不⼀致或冲突。MVCC的核⼼思想是每个事务在数据库中看到的数据版本是事务开始时的⼀个快照,⽽不是实际的最新版本这使得多个事务可以并发执⾏,⽽不会互相⼲扰。


MySQL的事务有ACID四⼤特性,其中的隔离性可以通过锁和MVCC来实现,MVCC适合在⼀些锁性能较为差的情况下使⽤,提⾼效率
 

如何实现:每⼀个 UndoLog ⽇志中都有⼀个 roll_pointer (回滚指针)⽤于指向上⼀个版本的 Undo Log 。这样对于每⼀条记录就会构成⼀个版本链,⽤于记录所有的修改,每⼀次进⾏新的修改后,新的Undo Log 会放在版本链的头部。

在进⾏查询的时候应该查询哪个版本,这可以通过 ReadView 来实现。
事务SELECT查询数据时,就会构造⼀个 ReadView ,它包含了版本链的统计信息

  • m_ids 当前活跃的所有事务id(所有未提交的事务)
  • min_trx_id 版本链尾的id
  • max_trx_id 下⼀个将要分配的事务id(版本链头事务id+1)
  • creator_trx_id 创建这个ReadView的事务的id 查询规则:

该版本是否为当前事务创建(读取⾃⼰修改的数据),如果是就返回,否则进⼊下⼀个判断
该版本的事务id是否⼩于min_trx_id(在ReadView创建之前,数据已经提交),可以直接访问
该版本的事务id是否⼤于max_trx_id(在ReadView创建后,该版本才开启),不能被访问
该版本事务id在[min_trx_id, max_trx_id]之间,则判断当前版本事务id是否在m_ids中,如果不在,说明事务已经提交可以访问,否则不能访问。


问题10

B+树的优势

1. 单点查询:B 树进⾏单个索引查询时,最快可以在 O(1) 的时间代价内就查到。从平均时间代价来看,会⽐ B+ 树稍快⼀些。但是 B 树的查询波动会⽐较⼤,因为每个节点即存索引⼜存记录,所以有时候访问到了⾮叶⼦节点就可以找到索引,⽽有时需要访问到叶⼦节点才能找到索引。B+ 树的⾮叶⼦节点不存放实际的记录数据,仅存放索引,数据量相同的情况下,B+树的⾮叶⼦节点可以存放更多的索引,查询底层节点的磁盘 I/O次数会更少。


2. 插⼊和删除效率:B+ 树有⼤量的冗余节点,删除⼀个节点的时候,可以直接从叶⼦节点中删除,甚⾄可以不动⾮叶⼦节点,删除⾮常快。B+ 树的插⼊也是⼀样,有冗余节点,插⼊可能存在节点的分裂(如果节点饱和),但是最多只涉及树的⼀条路径。B 树没有冗余节点,删除节点的时候⾮常复杂,可能涉及复杂的树的变形。


3. 范围查询:B+ 树所有叶⼦节点间有⼀个链表进⾏连接,⽽ B 树没有将所有叶⼦节点⽤链表串联起来的结构,因此只能通过树的遍历来完成范围查询,范围查询效率不如 B+ 树。B+ 树的插⼊和删除效率更⾼。存在⼤量范围检索的场景,适合使⽤ B+树,⽐如数据库。⽽对于⼤量的单个索引查询的场景,可以考虑 B 树,⽐如nosql的MongoDB。


问题11

索引失效的场景:

  1. OR 条件: 当查询中使⽤多个 OR 条件时,如果这些条件不涉及同⼀列,索引可能⽆法有效使⽤。数据库可能会选择全表扫描⽽不是使⽤多个索引。
  2. 对列进⾏类型转换: 如果在查询中对列进⾏类型转换,例如将字符列转换为数字或⽇期,索引可能会失效。
  3. 使⽤通配符前缀搜索: 在使⽤通配符前缀(如 LIKE 'prefix%' )进⾏搜索时,⼤多数索引⽆法使⽤,因为索引通常是按照列的完整值进⾏排序的。
  4. 不等号条件: 当查询中包含不等号条件(如>,<,>=,<=)时,索引可能会失效。通常情况下,索引只能⽤于等值⽐较。
  5. 表连接中的列类型不匹配: 如果在连接操作中涉及的两个表的列类型不匹配,索引可能会失效。例如,⼀个表的列是整数,另⼀个表的列是字符,连接时可能会导致索引失效。

写在最后

PS:以上是网络上收集的一些常见的问题以及自己对答案搜索整理;一次整理基本上就是面试一次的题量,适合对自己的知识的查缺补漏

面试一般根据岗位要求或者简历上写的来进行扩展提问,也有些是直接问公司常用到的相关方面的技术问题,无论怎么准备都祝大家能拿到心怡的offer!

  • 33
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值