技术-算法-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规模的输入。
相关推荐
jing-ya1 天前
day 57 图论part9
java·开发语言·数据结构·算法·图论
竹之却1 天前
国内外主流大模型全面解析(2026版)
服务器·大模型·国内外主流大模型·openclaw·云养虾
2401_894241921 天前
C++与Rust交互编程
开发语言·c++·算法
啊我不会诶1 天前
Codeforces Round 1083 (Div. 2)vp补题
c++·学习·算法
源远流长jerry1 天前
RDMA Memory Region (MR) 机制详解:地址转换与内存保护
linux·服务器·网络·tcp/ip·架构·mr
c++逐梦人1 天前
Linux进程信号
linux·服务器
cpp_25011 天前
P1203 [IOI 1993 / USACO1.1] 坏掉的项链 Broken Necklace
数据结构·c++·算法·线性dp
_小草鱼_1 天前
【搜索与图论】BFS(广度优先搜索)
算法·图论·bfs·宽度优先
weixin_421922691 天前
分布式日志系统实现
开发语言·c++·算法
逸Y 仙X1 天前
文章九:ElasticSearch索引字段常见属性
java·大数据·服务器·数据库·elasticsearch·搜索引擎