打点计数器的区间合并|豆包MarsCode AI刷题;

98 阅读4分钟

问题描述

小明正在设计一台打点计数器,该计数器可以接受多个递增的数字范围,并对这些范围内的每个唯一数字打点。如果多个范围之间有重叠,计数器将合并这些范围并只对每个唯一数字打一次点。小明需要你帮助他计算,在给定的多组数字范围内,计数器会打多少个点。

例如,给定三个数字范围 [1, 4], [7, 10], 和 [3, 5],计数器首先将这些范围合并,变成 [1, 5] 和 [7, 10],然后计算这两个范围内共有多少个唯一数字,即从 1 到 5 有 5 个数字,从 7 到 10 有 4 个数字,共打 9 个点。


测试样例

样例1:

输入:inputArray = [[1, 4], [7, 10], [3, 5]]
输出:9

样例2:

输入:inputArray = [[1, 2], [6, 10], [11, 15]]
输出:12

样例3:

输入:inputArray = [[1, 3], [2, 6], [8, 10]]
输出:9

题目分析

  1. 合并重叠范围:首先,我们需要将所有重叠的范围合并成一个连续的范围。这可以通过对输入的范围进行排序,然后逐个检查并合并重叠的范围来完成。
  2. 计算唯一数字的数量:一旦我们有了合并后的范围,我们就可以计算每个范围内有多少个唯一数字。这可以通过计算每个范围的上限和下限之间的差值加一来完成。

代码实现

import java.util.Arrays;

public class Main {

    public static int solution(int[][] ranges) {
        if (ranges.length == 0) {
            return 0;
        }
        // 按区间的起始点排序
        Arrays.sort(ranges, (a, b) -> Integer.compare(a[0], b[0]));

        int totalPoints = 0;
        int start = ranges[0][0];
        int end = ranges[0][1];

        for (int i = 1; i < ranges.length; i++) {
            int[] currentRange = ranges[i];
            // 如果当前区间与之前的区间有重叠或相邻,则合并区间
            if (currentRange[0] <= end + 1) {
                end = Math.max(end, currentRange[1]); // 更新结束点
            } else {
                // 计算非重叠区间的长度
                totalPoints += (end - start + 1); // 添加当前区间的长度
                // 更新新的区间
                start = currentRange[0];
                end = currentRange[1];
            }
        }
        // 加上最后一个合并后的区间
        totalPoints += (end - start + 1);

        return totalPoints;
    }
    public static void main(String[] args) {
        //  You can add more test cases here
        int[][] testArray1 = {{1, 4}, {7, 10}, {3, 5}};
        int[][] testArray2 = {{1, 2}, {6, 10}, {11, 15}};

        System.out.println(solution(testArray1) == 9);
        System.out.println(solution(testArray2) == 12);
    }
}

代码逻辑分析

  1. 初始化计数器和范围:初始化 totalPoints 变量为 0,用于存储最终的唯一数字总数。同时,初始化 startend 变量为第一个范围的起始点和结束点。

  2. 遍历范围:从第二个范围开始遍历排序后的范围数组。对于每个当前范围 currentRange

    • 如果 currentRange 的起始点小于或等于 end + 1,则表示当前范围与前一个范围重叠或相邻。在这种情况下,通过取 end 和 currentRange 的结束点的最大值来更新 end
    • 如果 currentRange 的起始点大于 end + 1,则表示当前范围与前一个范围不重叠。在这种情况下,计算前一个范围的长度(end - start + 1)并将其添加到 totalPoints 中。然后,更新 start 和 end 为当前范围的起始点和结束点。
  3. 计算最后一个范围的长度:在循环结束后,计算最后一个合并后的范围的长度(end - start + 1)并将其添加到 totalPoints 中。

时间复杂度分析

  1. 合并操作

    • 在 for 循环中,对于每个范围,代码执行的操作(比较和可能的赋值)都是常数时间操作,即 O(1)。因此,合并操作的总时间复杂度为 O(n)。
  2. 排序操作

    Arrays.sort 方法对范围数组进行排序,其时间复杂度为 O(n log n),其中 n 是范围数组的长度。这是因为 Java 中的 Arrays.sort 方法通常使用 Timsort 算法,它在最佳和平均情况下的时间复杂度为 O(n log n)。

总结

使用豆包MarsCode AI工具后,我的解题速度得到了显著提升,同时在知识整理和错题分析方面也有了长足的进步。我计划继续利用AI的功能结合传统学习资源,来加强我的算法基础,并挑战更高难度的题目。

希望我的这些经验能够对其他初学者有所启发和帮助。让我们共同享受学习算法带来的乐趣,并在这个过程中不断进步和成长!