简单负载均衡

题目描述

某工程师为了解决服务器负载过高的问题,决定使用多个服务器来分担请求消息。

现给定 k 台服务器(编号从 1 到 k),以及一批请求消息的信息,格式为到达时刻 负载大小,消息说明:

每个时刻最多只有一条消息到达;

负载大小表示服务器处理该消息所需时长。

请计算在负载分担规则下,哪些服务器处理的负载最高(服务器处理的负载为所处理的所有消息的负载累加和),并以升序返回这些服务器的编号。

负载分担规则:

按顺序循环分配服务器,如:有3台服务器且都空闲,分配的方式为 1->2->3->1... ;

如果某台服务器繁忙,则跳过该服务器;

如果一条消息到达时所有服务器繁忙,则丢弃这条消息。

解答要求

时间限制:1000ms, 内存限制:512MB

输入

第一行为服务器的个数 k,k 的范围 [1, 50000]

第二行为请求消息个数 n,n 的范围 [1, 50000]

随后的 n 行为各条消息的到达时刻和负载大小(注意并非按到达时刻升序给出)。

消息到达时刻的范围 [1, 10^9],负载大小的范围 [1, 10^9]

输出

处理负载最多的服务器编号,注意按升序输出。

样例

输入样例 1

java 复制代码
3
7
1 15
2 10
12 10
5 10
6 10
30 15
32 10

输出样例 1

java 复制代码
1 3

提示样例 1

根据输入信息,经过分析可得以下表:

到达时刻 消息负载 完成时刻(不包含) 分配服务器号
1 15 16 1
2 10 12 2
5 10 15 3
6 10 16 丢弃
12 10 22 2
30 15 45 3
32 10 42 1

根据上表分析,1和3号服务器处理的负载都为25,按照升序排列,输出的结果为:1 3

Java算法源码

java 复制代码
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Scanner;

public class Main {
    // 待实现函数,在此函数中填入答题代码
    static int[] findHighestLoadServers(int serverNum, Message[] messages) {
        boolean[] isBusy = new boolean[serverNum]; // 下标为server编号-1,值为是否忙碌
        int[] serverLoad = new int[serverNum]; // 下标为server编号-1,值为总Load
        Message[] processingMsg = new Message[serverNum]; // 下标为server编号-1,值为目前仍在处理的 message信息
        // 首先将消息按时间排序
        Arrays.sort(messages, Comparator.comparingInt(o -> o.time));
        int lastProcessIdx = -1; // 上次分配执行的服务器,从-1开始
        // 依次处理 messages
        for (Message message : messages) {
            // 首先更新时间
            updateTime(message.time, isBusy, processingMsg, serverNum);
            // 从 lastProcessIdx 下一个位置开始,循环找到第一个空闲的server
            // 按顺序循环分配服务器:i最大值可为 2 * serverNum,使用 i % serverNum 得到对应循环的下标
            for (int i = lastProcessIdx + 1; i < 2 * serverNum; i++) {
                // 不忙,说明找到空闲的Server
                if (!isBusy[i % serverNum]) {
                    processingMsg[i % serverNum] = message; // message添加到processingMsg
                    serverLoad[i % serverNum] += message.load; // 计算该server的总负载值
                    isBusy[i % serverNum] = true; // 标记该server为忙碌
                    lastProcessIdx = i % serverNum; // 记录下 lastProcessIdx 以下次循环使用
                    break;
                }
            }
        }
        // 统计结果
        List<int[]> idLoadArrList = new ArrayList<>(); // [serverId, serverLoad]
        for (int i = 0; i < serverNum; i++) {
            idLoadArrList.add(new int[] {i + 1, serverLoad[i]});
        }
        idLoadArrList.sort((o1, o2) -> o1[1] != o2[1] ? o2[1] - o1[1] : o1[0] - o2[0]); // 按serverLoad降序,serverId升序
        // 生成答案
        List<Integer> ansList = new ArrayList<>();
        ansList.add(idLoadArrList.get(0)[0]);
        int maxLoad = idLoadArrList.get(0)[1];
        int i = 1;
        // 将与最大值相等的serverId加入结果集
        while (i < idLoadArrList.size() && idLoadArrList.get(i)[1] == maxLoad) {
            ansList.add(idLoadArrList.get(i)[0]);
            i++;
        }
        return ansList.stream().mapToInt(Integer::valueOf).toArray();
    }
    
    private static void updateTime(int time, boolean[] isBusy, Message[] processingMsg, int serverNum) {
        for (int i = 0; i < serverNum; i++) {
            // 空闲的不处理
            if (!isBusy[i]) {
                continue;
            }
            // 忙碌的检查是否处理完了
            Message message = processingMsg[i];
            if (message.time + message.load <= time) {
                isBusy[i] = false;
                processingMsg[i] = null;
            }
        }
    }

    static class Message {
        int time;
        int load;
    };

    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in, StandardCharsets.UTF_8.name());
        int serverNum = cin.nextInt();
        int messageNum = cin.nextInt();
        Message[] messages = new Message[messageNum];
        for (int i = 0; i < messages.length; i++) {
            Message message = new Message();
            message.time = cin.nextInt();
            message.load = cin.nextInt();
            messages[i] = message;
        }

        cin.close();

        int[] highestLoadServers = findHighestLoadServers(serverNum, messages);
        String[] strResult = Arrays.stream(highestLoadServers).mapToObj(String::valueOf).toArray(String[]::new);
        System.out.println(String.join(" ", strResult));
    }
}
相关推荐
laoliu19961 小时前
Odoo 18企业版源码 包含 部署教程
运维·服务器
守城小轩1 小时前
基于Chrome140的Quora账号自动化(关键词浏览)——运行脚本(三)
运维·自动化·chrome devtools·指纹浏览器·浏览器开发
未来之窗软件服务2 小时前
幽冥大陆(五十五)ASR SetThreadInformation C语言识别到自动化软件
运维·自动化·asr·东方仙盟·操作系统级别错误
开开心心就好2 小时前
免费卸载工具,可清理残留批量管理启动项
linux·运维·服务器·windows·随机森林·pdf·1024程序员节
Lbwnb丶2 小时前
检测服务器是否是虚拟化,如KVM,VM等
linux·运维·服务器
老猿讲编程2 小时前
【车载信息安全系列4】基于Linux中UIO的HSE应用实现
linux·运维·服务器
鸡吃丸子2 小时前
初识Docker
运维·前端·docker·容器
wanhengidc3 小时前
巨椰 云手机 云游戏稳定运行
运维·服务器·arm开发·游戏·云计算
林义满3 小时前
大促零宕机背后的运维升级:长三角中小跨境电商的架构优化实践
大数据·运维·架构