02 打点计时器

129 阅读4分钟

打点计时器

问题描述(不计算右边界)

小明想发明一台打点计数器,这个计数器有这样的一个功能

  • 它可以接收一个递增的数据范围(形如[3, 9]),其中第一个数字代表起始,第二个数字代表结束
  • 这个数据范围中包含几个数字,打点计数器就会打几个点
  • 在传入的多组数据范围中,如果出现了范围的重复,机器则不会重复打点 你可以帮助小明算一算,在不同的情况下,计数器会打出几个点么?

输入格式

一个二维数组

输出格式

一个整数,表达在输入是这个数组的情况下,计数器打出的点数

输入样例(1)

[    [1,4],    [7, 10],    [3, 5] ]

输出样例(1)

7

输入样例(2)

[    [1,2],    [6, 10],    [11, 15] ]

输出样例(2)

9

数据范围

  • 数字范围 [-10^9, 10^9],数组长度 < 2^16

编码流程

理解题目

MarsCode
01 为什么输入样例1,会输出7

对于输入样例 1 [[1,4], [7, 10], [3, 5]],我们来分析一下。

第一个范围 [1, 4] 包含数字 1、2、3、4,一共 4 个数字。

第二个范围 [7, 10] 包含数字 7、8、9、10,一共 4 个数字。

第三个范围 [3, 5] 包含数字 3、4、5,但是 3、4 已经在第一个范围中出现过了,所以只计算 5,增加 1 个数字。

综上,总共的点数就是 4 + 4 + 1 = 7 。您明白了吗?

02 4+4+1难道不是等于9嘛?

不是的,4 + 4 + 1 = 9 是计算错误,正确的计算应该是 4 + 4 + 1 = 8 + 1 = 9 。但在这个题目中,第三个范围 [3, 5] 中的 3 和 4 已经在第一个范围 [1, 4] 中出现过了,所以只增加了 1 个新数字 5 ,因此总数是 4 + 4 + 1 = 7 。您理解了吗?

chatgpt

这个问题可以理解为计算多个区间的并集所覆盖的数字个数。

问题拆解:

  1. 区间合并:首先,我们会输入一系列区间。对于这些区间,有的区间可能会互相重叠,因此我们需要将重叠的区间合并,以避免重复计算打点数。
  2. 点数计算:在合并后的区间中,计算每个合并后区间的长度,所有长度之和就是最终的打点数。

解题步骤:

  1. 输入解析:我们接收一个二维数组,每个子数组表示一个区间 [start, end]
  2. 排序区间:首先根据每个区间的起点 start 进行排序。如果起点相同,按照终点 end 排序。
  3. 合并区间:依次遍历排序后的区间,判断是否与上一个区间重叠。如果重叠,则合并区间;否则将当前区间计入非重叠的结果中。
  4. 计算点数:对于每个非重叠的区间,计算其长度 (end - start + 1),然后累加所有区间的长度。

示例分析:

输入样例(1):

[
   [1,4],
   [7, 10],
   [3, 5]
]
  1. 对区间进行排序,得到:
    [
       [1,4],
       [3, 5],
       [7, 10]
    ]
    
  2. 合并区间:
    • 第一个区间 [1, 4] 与第二个区间 [3, 5] 重叠,合并为 [1, 5]
    • 第三个区间 [7, 10] 不与前面的区间重叠。
    • 合并后的区间是:[[1, 5], [7, 10]]
  3. 计算点数:
    • [1, 5] 的点数为 5。
    • [7, 10] 的点数为 4。
    • 总点数为 5 + 4 = 9

输入样例(2):

[
   [1,2],
   [6, 10],
   [11, 15]
]
  1. 对区间排序后,区间本身已经是有序且没有重叠的。
    • 合并结果为:[[1, 2], [6, 10], [11, 15]]
  2. 计算点数:
    • [1, 2] 的点数为 2。
    • [6, 10] 的点数为 5。
    • [11, 15] 的点数为 5。
    • 总点数为 2 + 5 + 5 = 12

总结:

  1. 排序区间。
  2. 合并重叠区间。
  3. 计算合并后的区间的总长度,输出结果。

你是否对这个思路有疑问,或者需要进一步的解释呢?

代码


#include <iostream>
#include <vector>

int solution(std::vector<std::vector<int>> inputArray) {
    // Please write your code here
    std::vector<int> end;
    for (int i = 0; i < inputArray.size(); i++) {
        int min = inputArray[i][0];
        int max = inputArray[i][inputArray[i].size()-1];
        for (int j = min; j < max; j++) {
            bool T = true;
            for (int k = 0; k < end.size(); k++) {
                if (end[k] == j) {
                    T = false;
                }
            }
            if (T) {
                end.push_back(j);
            }
        }
    }
    return end.size();
}

int main() {
    //  You can add more test cases here
    std::vector<std::vector<int>> testArray1 = { {1, 4}, {7, 10}, {3, 5} };
    std::vector<std::vector<int>> testArray2 = { {1, 2}, {6, 10}, {11, 15} };

    std::cout << (solution(testArray1) == 7) << std::endl;
    std::cout << (solution(testArray2) == 9) << std::endl;

    return 0;
}