华为OD机试真题----日志采集(java)

华为OD机试真题中的“日志采集”是一个重要的题目,它主要考察的是如何在满足特定条件下,优化日志上报策略以获取最大积分。以下是对该题目的详细解析:

一、题目背景

日志采集是运维系统的核心组件,日志是按行生成,每行记做一条,由采集系统分批上报。上报策略的设计需要平衡多个因素:上报频率、服务端压力、用户体验以及避免超时失败。

二、上报策略

根据题目描述,项目组设计了以下上报策略:

  1. 奖励机制:每成功上报一条日志,奖励1分。
  2. 扣分机制:每条日志每延迟上报1秒,扣1分。
  3. 强制上报条件:积累日志达到100条时,必须立即上报。

三、解题思路

解题的关键在于确定何时上报日志以获取最多的积分。这需要考虑日志的生成速度、上报的延迟以及积分奖励与扣除的平衡。

  1. 分析日志生成序列:首先,需要分析输入的日志生成序列(按时序产生的日志条数 T1, T2, …, Tn),了解日志的生成速度和总量。
  2. 模拟上报过程:然后,通过模拟上报过程,尝试在不同的时间点上报日志,并计算每种情况下的积分。在模拟过程中,需要考虑上述的奖励机制和扣分机制。
  3. 寻找最优解:最后,通过比较不同上报策略下的积分,找到能够获取最多积分的上报时间点。

四、代码实现

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.lang.Integer;

public class LogCollection {

    private static final Logger log = LoggerFactory.getLogger(LogCollection.class);

    public static int calculateMaxScore(int[] logCounts) {
        int maxScore = 0;
        List<Integer> logs = new ArrayList<>();
        for (int count : logCounts) {
            if (count < 0) {
                throw new IllegalArgumentException("Log counts cannot be negative.");
            }
            logs.add(count);
        }
        int[] accLogs = new int[logs.size()];

        accLogs[0] = logs.get(0);

        int[] penaltyScore = new int[logs.size()];
        penaltyScore[0] = 0;

        int[] totalScore = new int[logs.size()];;

        int currentTime = 0;
        int accumulatedLogs = 0;
        log.info("初始化:{},{},{}",accumulatedLogs,currentTime,maxScore);
        log.info("======================");
        for (int i = 0; i < logs.size(); i++) {
            log.info("logs["+i+"]=:{}",logs.get(i));
            // 计算累计日志数量,不能超过100
            accumulatedLogs += logs.get(i);
            log.info("累计日志数量:{}",  accumulatedLogs);
            accLogs[i] = Math.min(100, accumulatedLogs);
            // 计算惩罚分数,每延迟上报1秒,扣1分
            currentTime++;
            log.info("当前时间:{}",  currentTime);
            if (i > 0){
                penaltyScore[i] = penaltyScore[i - 1] + (currentTime - 1);
            }
            log.info(" 惩罚分数i:{}",  penaltyScore[i]);
            // 计算总分数 = 累计日志数量 - 惩罚分数
            totalScore[i] = accLogs[i] - penaltyScore[i];
            log.info(" 总分数:{}",  totalScore);
            log.info("---------------");
            // 如果日志数量大于等于100,停止遍历
            if (accumulatedLogs >= 100) {
                break;
            }
        }

        for (int item : totalScore) {
            if (item > maxScore) {
                maxScore = item;
            }
        }
        log.info("最大分数:{}",  maxScore);
        return maxScore;
    }

    public static void main(String[] args) {
        String[] parts = {"1","98","1"};
        int[] logCounts = new int[parts.length];

        for (int i = 0; i < parts.length; i++) {
            logCounts[i] = Integer.parseInt(parts[i]);
        }

        int maxScore = calculateMaxScore(logCounts);
        System.out.println(maxScore);
    }
}


五、示例解析

以示例输入“1 98 1”为例:

  • 采集系统在第1个时刻生成1条日志,第2个时刻生成98条日志,第3个时刻生成1条日志。

  • 如果在第1个时刻上报,由于只上报了1条日志,且没有延迟,所以积分为1。但后续98条日志将全部延迟上报,每条扣除1分,总计扣除98分,最终积分为-97(但实际操作中积分不会为负,这里仅作说明)。

  • 如果在第2个时刻上报,此时可以上报最多100条日志(因为已经积累了1+98=99条,再加上第2个时刻新生成的1条,达到100条的上报阈值)。前99条日志中,有98条延迟了1秒上报,每条扣除1分,总计扣除98分。但由于上报了100条日志,获得100分奖励,所以最终积分为100-98=2分(但根据规则,每上报一条日志即奖励1分,所以实际应为100分减去因延迟上报而扣除的分数后的剩余分数,即99分,但这里考虑到上报的即时性,我们假设第100条日志没有延迟上报,因此积分为100分)。然而,更合理的解释是,在第2个时刻上报时,由于达到了100条日志的阈值,必须立即上报,此时前98条日志延迟了1秒上报,扣除98分,但上报了100条日志获得100分奖励,因此最终积分为100-98+1(上报第100条日志的奖励)=3分。但题目中给出的答案是98分,这可能是因为题目假设了某种特殊的计算方式或理解上的偏差。在大多数情况下,我们会按照上述的逻辑进行计算。

  • 如果在第3个时刻上报,虽然可以上报所有日志且没有延迟,但由于此时已经超过了上报的最佳时机(即第2个时刻),所以积分将低于在第2个时刻上报的积分。

综上所述,对于示例输入“1 98 1”,最优的上报策略是在第2个时刻上报,以获取最多的积分(尽管具体积分值可能因理解上的差异而有所不同)。

六、注意事项

  • 在实际解题过程中,需要仔细阅读题目描述和示例说明,确保对上报策略有准确的理解。
  • 注意处理边界情况和特殊情况,如日志生成量刚好达到或超过100条时的上报策略。
  • 编写代码时,要注意算法的效率和正确性,确保能够在规定的时间内得出正确的结果。

七、详细示例解析

详细解释:
1、变量定义:

  • logs:输入的日志数量列表。
  • accLogs:累计日志数量数组。
  • penaltyScore:惩罚分数数组。 totalScore:总分数数组。
  • currentTime:当前时间。
  • accumulatedLogs:累计日志数量。

2、逻辑实现:

  • 初始化 accLogs 和 penaltyScore 数组。
  • 遍历输入的日志条数数组 logs。
  • 累加日志数量,并更新当前时间。
  • 计算累计日志数量,并确保不超过 100。
  • 计算惩罚分数。 计算总分数。
  • 如果累计日志数量达到 100 条,则停止遍历。
  • 找到最大得分。

3、主函数

  • 读取输入数据,并将其转换为整数列表。
  • 调用相关数组进行计算。
  • 输出最大得分。
    详细计算过程

1、初始化:

accumulatedLogs = 0, currentTime = 0, maxScore = 0

2、T1 时刻:

 - logs[0] = 1
 - accumulatedLogs = 1, currentTime = 1
 - accLogs[0] = 1
 - penaltyScore[0] = 0
 - totalScore[0] = 1 - 0 = 1
 - maxScore = 1

3、T2 时刻:

 - logs[1] = 98
 - accumulatedLogs = 99, currentTime = 2
 - accLogs[1] = 99
 - penaltyScore[1] = 0 + 1 = 1
 - totalScore[1] = 99 - 1 = 98
 - maxScore = 98

4、T3 时刻:

 - logs[2] = 1
 - accumulatedLogs = 100, currentTime = 3
 - accLogs[2] = 100
 - penaltyScore[2] = 1 + 2 = 3
 - totalScore[2] = 100 - 3 = 97
 - maxScore = 98

最终输出结果为 98
示例验证

输入:1 98 1
  • T1 时刻上报得 1 分。
  • T2 时刻上报得 98 分,最大。
  • T3 时刻上报得 97 分。
    输出结果应为 98。
    这样,代码就能正确计算首次上报的最大积分,并考虑时间延迟的影响。如果仍有问题,请告知具体的测试用例和期望输出,以便进一步调试
### 华为OD 转盘寿司 编程题 解法 #### 题目描述 在一个寿司转盘上有 `n` 盘寿司,每盘寿司有一个对应的价格数组 `prices[]`。当顾客选择一盘寿司时,店铺会免费赠送距离该盘最近的一盘价格更低的寿司。如果不存在这样的寿司,则不赠送。 #### 思路分析 为了高效解决这个问题,可以采用栈来辅助处理。具体来说: - 使用一个单调递减栈存储索引位置。 - 对于每一个新遇到的寿司,检查栈顶元素是否符合条件(即栈顶元素对应的寿司价格大于当前寿司),如果是则更新结果并弹出栈顶;否则继续压入新的索引到栈中。 这种方法能够在线性时间内完成计算,时间复杂度为 O(n),空间复杂度也为 O(n)。 #### Java 实现代码 ```java import java.util.*; public class SushiTurntable { public static int[] findFreeSushis(int[] prices) { Stack<Integer> stack = new Stack<>(); int n = prices.length; int[] result = new int[n]; Arrays.fill(result, -1); // 初始化result,默认值设为-1表示无匹配 for (int i = 0; i < n * 2; ++i) { // 循环两次模拟循环链表效果 while (!stack.isEmpty() && prices[stack.peek()] > prices[i % n]) { result[stack.pop()] = i % n; } if (i < n) { stack.push(i); } } return result; } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); String input = "7\n3 8 5 6 9 4 1"; String[] inputs = input.split("\n"); int n = Integer.parseInt(inputs[0]); int[] prices = Arrays.stream(inputs[1].split(" ")) .mapToInt(Integer::parseInt).toArray(); int[] freeSushisIndices = findFreeSushis(prices); System.out.println(Arrays.toString(freeSushisIndices)); } } ``` 此程序实现了上述逻辑,并通过读取标准输入获取数据进行测[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值