单选题
1.假设你有一个包含N个元素的数组,你想要找到数组中最大的两个数。以下哪种方法的时间复杂度最低?( D )
A.对数组进行排序,然后返回最后两个元素
B.使用两次嵌套循环比较所有可能的元素对,找到最大的两个数
C.先遍历一次数组找到最大值,再遍历一次去除最大值后的数组找到第二大的值
D.遍历数组一次,同时追踪最大值和次大值
2.下列哪种数组的方法不会修改数组本身?(A)
A. slice
B. splice
C. sort
D. unshift
3.下列更适合使用Object而不是Map的场景的是(A)
A.将数据结构序列化为JSON
B.可能是除字符串和Symbol外的其他类型
C.频繁进行增删操作
D.需要进行复杂的遍历操作
解析:
Object更适合用于简单的数据存储和JSON序列化,特别是当键是字符串且数据结构相对静态时。
Map更适合用于需要键的类型多样、频繁进行增删操作以及需要更灵活的遍历的场景。
4.给定一个整数数组nums和一个整数k,请编写一个函数来返回该数组中第k大的元素。你可以假设k总是有效的,并且1≤k≤数组的长度。( C )
A.对数组进行排序,然后返回排序后数组的第k个最大值
B.使用一个小顶堆(优先队列)来维护数组中的前k个最大元素
C.使用快速选择算法,它是快速排序的变种,在平均情况下能在O(n)时间内找到第k大的元素
D.遍历数组并使用计数排序的方法来统计每个数字出现的次数,然后根据这些统计结果找出第k大的元素
5.在建立TCP连接时,使用了三次握手协议。以下哪个步骤不是三次握手的一部分?(D)
A.客户端发送SYN包
B.服务端返回SYN-ACK包
C.客户端发送ACK包
D.客户端发送FIN包
解析:
第一次握手:客户端发送一个带有SYN标志的数据包,请求建立连接(SYN包)。
第二次握手:服务器收到客户端的SYN包后,回应一个SYN-ACK包,表示同意建立连接并确认收到SYN包。
第三次握手:客户端收到服务器的SYN-ACK包后,再发送一个ACK包向服务器确认。至此,连接建立成功。
6.以下哪种技术允许浏览器从同一个域名请求多个资源,而无需为每个资源建立新的TCP连接?(C )
A. HTTP/1.0
B. HTTP/1.1持久连接(Persistent Connections)
C. HTTP/2多路复用(Multiplexing)
D. WebSockets
解析:
HTTP/1.1 持久连接仅支持顺序处理多个请求(复用同一个 TCP 连接,但无法并发)。
HTTP/2多路复用通过二进制分帧实现真正并发(多个请求/响应可交错传输)。
多选题
1.以下哪些描述正确地反映了浏览器、网络和CDN的工作原理?(ABC)
A.CDN(内容分发网络)通过将内容缓存到多个地理位置的服务器上来加速内容交付。
B.浏览器在发送HTTP请求时,会首先检查本地缓存是否有对应的资源。
C.使用CDN可以减少服务器的负载并提高网站的可用性。
D.浏览器在解析HTML文档时,会阻塞渲染,直到所有外部JavaScript文件加载完成。
E.CDN只能用于静态内容的分发,动态内容无法通过CDN加速。
编程题
1.反转单向链表(leetcode206)
迭代法
public ListNode reverseList(ListNode head) {
ListNode prev = null; // 指向前一个节点,初始为 null
ListNode curr = head; // 指向当前节点,初始为 head
while (curr != null) {
ListNode next = curr.next; // 保存下一个节点,因为稍后要修改 curr.next
curr.next = prev; // 将当前节点的 next 指针指向前一个节点,实现反转
prev = curr; // 将 prev 移动到当前节点
curr = next; // 将 curr 移动到下一个节点
}
return prev; // 循环结束后,prev 指向的就是反转后的头节点
}
递归法
public ListNode reverseList(ListNode head) {
// 递归终止条件:链表为空或者只有一个节点
if (head == null || head.next == null) {
return head;
}
// 递归调用,反转 head.next 开始的链表
ListNode newHead = reverseList(head.next);
// 反转当前节点
head.next.next = head; // 将 head.next 的 next 指针指向 head
head.next = null; // 将 head 的 next 指针指向 null,防止循环链表
return newHead; // 返回反转后的头节点
}
2.最小时差:(leetcode539)
给定一个24小时制(小时:分钟 "HH:MM”)的时间列表,找出列表中任意两个时间的最小时间差并以分钟数表示。
示例1
输入
[“23:59”,“00:00”]
输出
1
示例2
输入
[“00:00”,“23:59”, “00:00”]
输出
0
题解
public int findMinDifference(List<string> timePoints) {
// 鸽巢原理优化:如果时间点的数量超过 1440 (一天的总分钟数),
// 那么必定存在重复的时间点,最小时间差为 0
if (timePoints.size() > 1440) {
return 0;
}
// 创建一个 HashSet 来存储已经出现的时间(以分钟为单位)。
Set<integer> timeSet = new HashSet<>();
// 创建一个 ArrayList 来存储转换后的时间(以分钟为单位)。
List<integer> minutes = new ArrayList<>();
// 遍历输入的字符串列表 (timePoints),将每个时间字符串转换为分钟
for (String time : timePoints) {
String[] parts = time.split(":");
int hour = Integer.parseInt(parts[0]);
int minute = Integer.parseInt(parts[1]);
int totalMinutes = hour * 60 + minute;
// 发现重复的时间点,直接返回 0
if (timeSet.contains(totalMinutes)) {
return 0;
}
// 将当前时间添加到 HashSet 中,标记为已出现
timeSet.add(totalMinutes);
// 将当前时间添加到 ArrayList 中,用于后续排序和计算
minutes.add(totalMinutes);
}
// 对存储分钟的 ArrayList 进行升序排序
Collections.sort(minutes);
// 初始化最小时间差为最大整数值,以便后续比较和更新
int minDiff = Integer.MAX_VALUE;
for (int i = 1; i < minutes.size(); i++) {
// 遍历排序后的分钟列表,计算相邻时间点的时间差,
// 并与当前最小时间差比较,更新 minDiff
minDiff = Math.min(minDiff, minutes.get(i) - minutes.get(i - 1));
}
// 计算第一个时间和最后一个时间的差值 (考虑跨天的情况),1440 是一天的总分钟数
// 这一步是为了解决 "00:00" 和 "23:59" 之间的时间差问题
int headTailDiff = minutes.get(0) + 1440 - minutes.get(minutes.size() - 1);
// 将首尾时间差与当前的最小时间差比较,更新 minDiff
minDiff = Math.min(minDiff, headTailDiff);
// 返回计算得到的最小时间差
return minDiff;
}