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

46 阅读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. 输入检查
    • 如果 inputArraynull 或长度小于 1,返回 0。
  1. 特殊情况处理
    • 如果 inputArray 只有一个区间,直接返回该区间的长度。
  1. 排序
    • 按区间的起始位置对 inputArray 进行排序。
  1. 合并区间
    • 初始化结果 res 为第一个区间的长度。
    • 初始化 maxt 为第一个区间的结束位置。
    • 遍历排序后的区间,根据当前区间的起始位置和 maxt 的关系,更新 resmaxt

复杂度分析

时间复杂度分析

  1. 输入检查
  • 这一步的时间复杂度是 O(1)。
  1. 特殊情况处理
  • 这一步的时间复杂度是 O(1)。
  1. 排序
  • 使用 Arrays.sortinputArray 进行排序。对于 n 个区间的排序,时间复杂度是 O(nlog⁡n)。
  1. 初始化结果和最大结束位置
  • 这一步的时间复杂度是 O(1)。
  1. 遍历排序后的区间
  • 遍历 n 个区间,时间复杂度是 O(n)。
  • 在遍历过程中,每个区间的操作(如比较、更新 resmaxt)都是 O(1) 的操作。

综上所述,总的时间复杂度为: O(1)+O(1)+O(nlog⁡n)+O(1)+O(n)=O(nlog⁡n)

空间复杂度分析

  1. 输入检查
  • 这一步的空间复杂度是 O(1)。
  1. 特殊情况处理
  • 这一步的空间复杂度是 O(1)。
  1. 排序
  • Arrays.sort 的空间复杂度是 O(log⁡n)(因为排序算法通常使用递归,递归栈的深度为 O(log⁡n)。
  1. 初始化结果和最大结束位置
  • 这一步的空间复杂度是 O(1)。
  1. 遍历排序后的区间
  • 这一步的空间复杂度是 O(1)。

综上所述,总的空间复杂度为: O(1)+O(1)+O(log⁡n)+O(1)+O(1)=O(log⁡n)

代码实现

Java代码实现

import java.util.Arrays;

public class Main {
    public static int solution(int[][] inputArray) {
        if (inputArray == null || inputArray.length < 1) return 0;
        int n = inputArray.length;
        
        // 特殊情况处理
        if (n == 1) {
            return inputArray[0][1] - inputArray[0][0] + 1;
        }
        
        // 按区间的起始位置排序
        Arrays.sort(inputArray, (p, q) -> p[0] - q[0]);
        
        // 初始化结果和最大结束位置
        int res = inputArray[0][1] - inputArray[0][0] + 1;
        int maxt = inputArray[0][1];
        
        // 遍历排序后的区间
        for (int i = 1; i < n; i++) {
            if (inputArray[i][0] > maxt) {
                // 当前区间与前一个区间不重叠
                res += (inputArray[i][1] - inputArray[i][0] + 1);
            } else if (inputArray[i][1] > maxt) {
                // 当前区间与前一个区间部分重叠
                res += (inputArray[i][1] - maxt);
            }
            // 更新最大结束位置
            if (inputArray[i][1] > maxt) {
                maxt = inputArray[i][1];
            }
        }
        
        return res;
    }

    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);
    }
}

Go 代码实现

package main

import (
	"fmt"
	"sort"
)

func solution(inputArray [][]int) int {
    if inputArray == nil || len(inputArray) < 1 {
		return 0
	}
	n := len(inputArray)

	// 特殊情况处理
	if n == 1 {
		return inputArray[0][1] - inputArray[0][0] + 1
	}

	// 按区间的起始位置排序
	sort.Slice(inputArray, func(i, j int) bool {
		return inputArray[i][0] < inputArray[j][0]
	})

	// 初始化结果和最大结束位置
	res := inputArray[0][1] - inputArray[0][0] + 1
	maxt := inputArray[0][1]

	// 遍历排序后的区间
	for i := 1; i < n; i++ {
		if inputArray[i][0] > maxt {
			// 当前区间与前一个区间不重叠
			res += (inputArray[i][1] - inputArray[i][0] + 1)
		} else if inputArray[i][1] > maxt {
			// 当前区间与前一个区间部分重叠
			res += (inputArray[i][1] - maxt)
		}
		// 更新最大结束位置
		if inputArray[i][1] > maxt {
			maxt = inputArray[i][1]
		}
	}

	return res
}

func main() {
    //  You can add more test cases here
    testArray1 := [][]int{{1, 4}, {7, 10}, {3, 5}}
    testArray2 := [][]int{{1, 2}, {6, 10}, {11, 15}}

    fmt.Println(solution(testArray1) == 9)
    fmt.Println(solution(testArray2) == 12)
}