70打点计数器题解 | 豆包MarsCode AI刷题

156 阅读3分钟

问题描述

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

例如,给定三个数字范围 [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

代码

int solution(std::vector<std::vector<int>> inputArray) {
  // 请在这里写你的代码
  vector<int> a(10000, 0);  // 使用一个长度为10000的数组,标记每个数字是否被访问过
  int count = 0;  // 记录唯一数字的个数
  for (int i = 0; i < inputArray.size(); i++) {  // 遍历每一个区间
    vector<int> b = inputArray[i];  // 获取当前区间
    for (int j = b[0]; j <= b[1]; j++) {  // 遍历区间的每个数字
      if (a[j] == 0) {  // 如果该数字未被计数过
        a[j] = 1;  // 标记该数字已经被计数
        count++;  // 增加计数
        cout << "j" << j << endl;  // 输出当前数字,调试用
      }
    }
  }

  return count;  // 返回唯一数字的总数
}
  • 数据结构
    vector<int> a(10000, 0) 创建了一个长度为 10000 的数组(假设输入的数字范围不超过 [0, 9999])。数组的每个元素用于标记某个数字是否已经被计算过。

    • a[j] = 0 表示数字 j 未被计数过。
    • a[j] = 1 表示数字 j 已经被计数过。
  • 遍历每个区间
    代码通过两层循环来遍历所有的数字范围。外层循环遍历每一个区间,内层循环遍历当前区间内的所有数字。

    • b[0]b[1] 分别是区间的起始和结束数字。
    • 内层循环 for (int j = b[0]; j <= b[1]; j++) 遍历当前区间的所有数字。
  • 计数唯一数字
    对于每个数字,如果它没有被计数过(即 a[j] == 0),则:

    • 标记为已计数(a[j] = 1)。
    • 增加 count,表示我们找到了一个唯一的数字。
  • 调试输出
    cout << "j" << j << endl; 这行代码在调试时输出每个被计数的数字。

  • 返回结果
    最终返回 count,表示所有唯一数字的总数。

改进方向

  • 优化空间使用
    使用 std::set 来存储已处理的数字,避免使用固定大小的数组。

  • 合并区间
    在计算前,先将所有区间合并。排序区间的起始位置,并合并重叠或相邻的区间,最后计算合并后区间内的数字总数。

  • 复杂度分析

    • 当前代码的时间复杂度为 O(m * n),其中 m 是区间数,n 是每个区间的大小。
    • 使用 set 可以将空间复杂度降低为 O(K),其中 K 是所有唯一数字的总数,且时间复杂度为 O(K * log(K))。