告警ID统计

76 阅读5分钟

告警ID统计

问题背景

在一个系统中,存在两块独立的单板。每块单板都会产生告警,这些告警的唯一标识(告警ID)分别存储在两个列表 arrayAarrayB 中。为了进行统一的监控和管理,需要将两块单板上报的所有告警ID进行合并、去重和排序。

任务要求

请实现一个程序,统计系统中所有出现过的告警ID。具体处理步骤如下:

  1. 合并: 将列表 arrayAarrayB 中的所有告警ID合并成一个集合。
  2. 去重: 如果同一个告警ID在两个列表或单个列表中出现多次,最终结果中只保留一个。
  3. 排序: 将去重后的告警ID,按照其十六进制数值的升序进行排列。

告警ID格式

  • 告警ID是一个无符号整数,以十六进制字符串的形式表示。
  • 字符串由 0-9 的数字字符和大写字母 A-F 组成。
  • 每个告警ID字符串的长度固定为 8个字符

输入格式

  • arrayA: 第一个参数,一个字符串列表,代表第一块单板的告警ID。

    • 0 <= arrayA.length <= 1000
  • arrayB: 第二个参数,一个字符串列表,代表第二块单板的告警ID。

    • 0 <= arrayB.length <= 1000

输出格式

  • 一个字符串列表,其中包含所有去重后、并按数值升序排列的告警ID。

样例说明

样例输入

arrayA = ["00001001", "00ABCD00"]
arrayB = ["FFFFFAAB", "FFFFFAAB", "00ABCD00"]

样例输出

["00001001", "00ABCD00", "FFFFFAAB"]

解释

  1. 合并与去重:

    • arrayAarrayB 合并,得到所有出现过的告警ID集合:

      • "00001001" (来自 arrayA)
      • "00ABCD00" (在 arrayAarrayB 中都存在,去重后保留一个)
      • "FFFFFAAB" (在 arrayB 中出现两次,去重后保留一个)
    • 去重后的唯一告警ID集合为: {"00001001", "00ABCD00", "FFFFFAAB"}

  2. 排序:

    • 根据十六进制数值的大小对这三个ID进行升序排序。
    • 比较数值大小: 0x00001001\<0x00ABCD00\<0xFFFFFAAB0x00001001 \< 0x00ABCD00 \< 0xFFFFFAAB
    • (由于所有字符串长度相同,直接按字典序排序即可得到数值排序的结果)
  3. 最终输出:

    • 排序后的列表为 ["00001001", "00ABCD00", "FFFFFAAB"]
import java.util.*;

/**
 * 解决思路:
 * 1.  **合并与去重**:使用 `HashSet` 数据结构来存储所有告警ID。`Set` 的特性是内部元素不重复,
 * 因此将两个数组的所有元素添加到 `Set` 中,就可以自动完成合并和去重。
 * 2.  **排序**:题目要求按告警ID所代表的**数值大小**升序排列,而不是字符串的字典序。
 * 因此,不能直接对字符串列表进行排序。正确的做法是:
 * a. 将去重后的 `Set` 转换为 `List`。
 * b. 使用 `Collections.sort()` 或 `List.sort()`,并提供一个自定义的 `Comparator`。
 * c. 在这个 `Comparator` 中,将两个待比较的十六进制字符串转换为长整型 (`long`) 数值,然后比较这两个数值。
 * 3.  **数值转换**:由于告警ID是无符号整数,一个8位的十六进制字符串(如 "FFFFFFFF")所代表的数值会超出 Java `int` 的正数范围。
 * 因此,使用 `Long.parseUnsignedLong(hexString, 16)` 是最安全和正确的方法,它可以正确地将十六进制字符串解析为无符号数值进行比较。
 * 其实8位这个长度用parseLong也行
 */
public class Main {
    /**
     * 核心逻辑方法:合并、去重并按数值排序告警ID。
     *
     * @param arrayA 第一个告警ID列表 (十六进制字符串数组)
     * @param arrayB 第二个告警ID列表 (十六进制字符串数组)
     * @return 一个包含所有唯一告警ID的列表,按其代表的数值大小升序排列。
     */
    public static List<String> processAlarms(String[] arrayA, String[] arrayB) {
        // 步骤 1 & 2: 合并与去重
        // 使用 HashSet 可以高效地完成合并和去重,因为 Set 不允许重复元素。
        Set<String> uniqueAlarmsSet = new HashSet<>();

        // 将第一个数组的元素添加到 Set 中
        if (arrayA != null) {
            // Collections.addAll 比手动循环更简洁
            Collections.addAll(uniqueAlarmsSet, arrayA);
        }
        // 将第二个数组的元素添加到 Set 中,重复的ID会被自动忽略
        if (arrayB != null) {
            Collections.addAll(uniqueAlarmsSet, arrayB);
        }

        // 步骤 3: 将 Set 转换为 List,以便进行排序
        List<String> resultList = new ArrayList<>(uniqueAlarmsSet);

        // 步骤 4: 使用自定义比较器进行排序
        // sort 方法接收一个 Comparator lambda 表达式
        resultList.sort((hexStr1, hexStr2) -> {
            // 核心比较逻辑:按十六进制字符串代表的数值大小进行比较

            // 使用 Long.parseUnsignedLong(string, 16) 将8位十六进制字符串
            // 安全地解析为一个无符号的数值(存储在 long 类型中)。
            // 这样做可以正确处理像 "FFFFFFFF" 这样的大数值。
            long val1 = Long.parseUnsignedLong(hexStr1, 16);
            long val2 = Long.parseUnsignedLong(hexStr2, 16);

            // Long.compare(val1, val2) 会返回 -1, 0, 或 1,
            // 实现了标准的升序比较。
            return Long.compare(val1, val2);
        });

        // 步骤 5: 返回排序后的列表
        return resultList;
    }


    // --- 主函数处理 ACM 输入输出 ---
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 读取两行输入
        // 假设输入格式为一行一个数组,数组内部元素以空格分隔
        // 例如:
        // 00001001 00ABCD00
        // FFFFFAAB FFFFFAAB 00ABCD00
        String lineA = scanner.nextLine();
        String lineB = scanner.nextLine();
        scanner.close();

        // 根据空格分割字符串,并处理可能的空行输入
        String[] arrayA = lineA.trim().isEmpty() ? new String[0] : lineA.trim().split("\s+");
        String[] arrayB = lineB.trim().isEmpty() ? new String[0] : lineB.trim().split("\s+");

        // 调用核心逻辑
        List<String> result = processAlarms(arrayA, arrayB);

        // 按题目要求的格式打印输出
        // 例如:["00001001", "00ABCD00", "FFFFFAAB"]
        System.out.println(result.toString().replace(" ", ""));
    }
}