简单负载均衡

题目描述

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

现给定 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));
    }
}
相关推荐
乘云数字DATABUFF17 小时前
5分钟部署开源APM Databuff:OpenTelemetry全链路追踪入门实战
运维·后端
荣--3 天前
一键部署不是为了省时间 —— 它是把"买来的 PaaS"变成"自己的平台"的拐点
运维·zabbix·工程化·一键部署·平台化·边界设计
江华森3 天前
动手实战学 Docker — 从零到集群编排完全指南
运维
Avan_菜菜3 天前
FRP 内网穿透完整实战:从 HTTP 映射到 HTTPS 自签代理
运维·nginx·https
SelectDB4 天前
Litefuse 开源并推出单进程轻量模式,25 秒就能跑起来的 Agent 可观测与评估平台
运维·后端·自动化运维
XIAOHEZIcode6 天前
Linux系统鼠标偏移常见原因以及修复方案
linux·运维·游戏
用户0328472220706 天前
如何搭建本地yum源(上)
运维
大树889 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠9 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质9 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务