技术-算法-leetcode-1606. 找到处理最多请求的服务器(易懂版)

你需要解决的是服务器请求分配问题:给定k个环形排列的服务器和按时间递增到达的请求,按指定规则分配请求后,找出处理请求数量最多的所有服务器编号。这个问题的核心是高效管理服务器的空闲/忙碌状态,因为数据量(k和请求数)可达10^5,暴力解法会超时。

解题思路

要高效解决这个问题,需要两个核心数据结构:

  1. 有序集合(TreeSet):维护当前空闲的服务器编号,支持快速查找"i%k之后第一个空闲的服务器"(环形查找)。
  2. 最小堆(PriorityQueue):维护当前忙碌的服务器,存储(服务器结束时间,服务器编号),支持快速取出"最早结束的服务器",以便及时将其放回空闲集合。

具体步骤:

  1. 初始化空闲服务器集合(包含0~k-1)、忙碌服务器堆、请求计数数组。
  2. 遍历每个请求:
    • 先清理忙碌堆:将所有结束时间≤当前请求到达时间的服务器放回空闲集合。
    • 如果无空闲服务器,舍弃该请求。
    • 否则,按规则找到目标服务器:
      • 计算目标起点 target = i % k
      • 在空闲集合中找≥target的第一个服务器;若不存在,取空闲集合中最小的服务器(环形特性)。
    • 更新服务器状态:从空闲集合移除目标服务器,加入忙碌堆,计数数组+1。
  3. 遍历计数数组,找到最大值,收集所有等于最大值的服务器编号。

完整Java代码

java 复制代码
import java.util.*;

public class BusiestServers {
    public List<Integer> busiestServers(int k, int[] arrival, int[] load) {
        // 1. 初始化数据结构
        // 空闲服务器集合:有序,支持快速查找/删除
        TreeSet<Integer> freeServers = new TreeSet<>();
        for (int i = 0; i < k; i++) {
            freeServers.add(i);
        }
        
        // 忙碌服务器堆:最小堆,元素为[结束时间, 服务器编号],按结束时间升序
        PriorityQueue<int[]> busyServers = new PriorityQueue<>(Comparator.comparingInt(a -> a[0]));
        
        // 记录每个服务器处理的请求数
        int[] count = new int[k];
        
        // 2. 处理每个请求
        int n = arrival.length;
        for (int i = 0; i < n; i++) {
            int arriveTime = arrival[i];
            int processTime = load[i];
            int endTime = arriveTime + processTime;
            
            // 步骤1:清理忙碌堆,将已完成的服务器放回空闲集合
            while (!busyServers.isEmpty() && busyServers.peek()[0] <= arriveTime) {
                int freeServer = busyServers.poll()[1];
                freeServers.add(freeServer);
            }
            
            // 步骤2:无空闲服务器,舍弃请求
            if (freeServers.isEmpty()) {
                continue;
            }
            
            // 步骤3:按规则找目标服务器
            int target = i % k;
            Integer selectedServer = freeServers.ceiling(target); // 找≥target的第一个空闲服务器
            if (selectedServer == null) {
                selectedServer = freeServers.first(); // 环形,取最小的空闲服务器
            }
            
            // 步骤4:更新服务器状态和计数
            freeServers.remove(selectedServer);
            busyServers.offer(new int[]{endTime, selectedServer});
            count[selectedServer]++;
        }
        
        // 3. 找出处理请求最多的服务器
        List<Integer> result = new ArrayList<>();
        int maxCount = 0;
        for (int c : count) {
            maxCount = Math.max(maxCount, c);
        }
        for (int i = 0; i < k; i++) {
            if (count[i] == maxCount) {
                result.add(i);
            }
        }
        
        return result;
    }

    // 测试用例
    public static void main(String[] args) {
        BusiestServers solution = new BusiestServers();
        // 示例1
        int k1 = 3;
        int[] arrival1 = {1,2,3,4,5};
        int[] load1 = {5,2,3,3,3};
        System.out.println(solution.busiestServers(k1, arrival1, load1)); // 输出[1]
        
        // 示例2
        int k2 = 3;
        int[] arrival2 = {1,2,3,4};
        int[] load2 = {1,2,1,2};
        System.out.println(solution.busiestServers(k2, arrival2, load2)); // 输出[0]
    }
}

代码关键部分解释

  1. TreeSet的核心操作
    • ceiling(target):返回≥target的最小元素,对应"找i%k之后第一个空闲服务器"。
    • first():返回集合中最小元素,对应环形查找时"从0开始找第一个空闲服务器"。
  2. PriorityQueue的核心作用
    • 按结束时间升序排列,确保每次能优先取出最早完成的服务器,及时释放资源。
  3. 计数数组
    • 简单直观地记录每个服务器处理的请求数,最后遍历即可找到最大值和对应服务器。

复杂度分析

  • 时间复杂度:O(n log k)。每个请求的堆操作(poll/offer)和集合操作(add/remove/ceiling)都是O(log k),n个请求总复杂度为O(n log k),满足10^5数据量的要求。
  • 空间复杂度:O(k)。空闲集合、忙碌堆、计数数组的空间均不超过k。

总结

  1. 核心数据结构:用TreeSet高效管理空闲服务器(支持环形查找),用PriorityQueue高效管理忙碌服务器(按结束时间排序)。
  2. 关键逻辑:处理每个请求前先清理已完成的服务器,再按环形规则查找目标空闲服务器。
  3. 效率保障:所有核心操作都是O(log k)级别,整体算法能高效处理10^5规模的输入。
相关推荐
JieE2128 小时前
LeetCode 56. 合并区间|超清晰 JS 图解思路,面试高频区间题
javascript·算法·面试
Jack2015 小时前
HarmonyOS开发中错误处理策略:网络异常统一处理
算法
小小杨树17 小时前
读懂色彩:拍照调色不再难
算法·计算机视觉·配色
JieE2121 天前
LeetCode 226. 翻转二叉树|JS 递归超详细拆解,二叉树入门经典题
javascript·算法
JieE2121 天前
LeetCode 104. 二叉树的最大深度|递归思路超详细拆解
javascript·算法
vivo互联网技术2 天前
CVPR 2026 | 全新强化学习框架 BeautyGRPO:重塑真实人像
算法·大模型·cvpr·影像
Darling噜啦啦2 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
用户497863050732 天前
(一)小红的数组操作
算法·编程语言
怕浪猫2 天前
Electron 系列文章封面图
算法·架构·前端框架