青训营X豆包MarsCode 技术训练营:理想火车站定位Python3题解| 豆包MarsCode AI 刷题

59 阅读6分钟

理想火车站定位

问题描述

小F是A市的市长,正在计划在A市新建一个火车站以方便市民的日常出行。市区内的街道布局十分规整,形成网格状。从一个位置[x1, y1]到另一个位置[x2, y2]的距离计算方法为 |x1 - x2| + |y1 - y2|,即曼哈顿距离。

在初步考察后,市政府列出了M个可能的火车站建设点。为了使得市民到火车站的总旅行时间最短,小F希望选出一个最优位置作为火车站的地址。

请你帮助小F计算出哪一个位置最适合建设新火车站。

  • N: 市民的总人数。
  • M: 可建设火车站的备选位置数。
  • citizens: 一个列表,每个元素是一个元组 [x_i, y_i],表示第 i 位市民的居住位置。
  • locations: 一个列表,每个元素是一个元组 [p_i, q_i],表示第 i 个备选的火车站位置。

如果有多个火车站最优,那么选择第一次出现的那个。

测试样例

样例1:

输入:n = 4, m = 3, citizens = [[-1, -1], [-1, 1], [1, -1], [1, 1]], locations = [[3, 2], [1, 0], [0, 0]] 输出:[1, 0]

样例2:

输入:n = 2, m = 2, citizens = [[0, 0], [0, 4]], locations = [[0, 2], [0, 3]] 输出:[0, 2]

样例3:

输入:n = 3, m = 1, citizens = [[10, 10], [20, 20], [30, 30]], locations = [[15, 15]] 输出:[15, 15]

样例4:

输入:n = 5, m = 3, citizens = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]], locations = [[4, 5], [6, 7], [8, 9]] 输出:[4, 5]

样例5:

输入:n = 6, m = 2, citizens = [[10, 10], [20, 20], [30, 30], [40, 40], [50, 50], [60, 60]], locations = [[35, 35], [45, 45]] 输出:[35, 35]

解题思路

问题理解

我们需要在给定的 M 个备选火车站位置中,选择一个位置,使得所有市民到该位置的总曼哈顿距离最小。曼哈顿距离的计算公式为 |x1 - x2| + |y1 - y2|

数据结构选择

  • 市民位置:使用一个列表 citizens,其中每个元素是一个元组 [x_i, y_i],表示第 i 位市民的居住位置。
  • 火车站位置:使用一个列表 locations,其中每个元素是一个元组 [p_i, q_i],表示第 i 个备选的火车站位置。

算法步骤

  1. 初始化

    • 初始化一个变量 min_total_distance 来存储最小的总距离,初始值为一个很大的值(例如 float('inf'))。
    • 初始化一个变量 best_location 来存储最优的火车站位置,初始值为 [-1, -1]
  2. 遍历所有火车站位置

    • 对于每个火车站位置 loc,计算它到所有市民的总距离。
  3. 计算总距离

    • 对于每个市民位置 citizen,计算它到当前火车站位置 loc 的曼哈顿距离,并累加到 total_distance
  4. 更新最优位置

    • 如果当前的总距离 total_distance 小于 min_total_distance,则更新 min_total_distance 和 best_location
  5. 返回结果

    • 遍历完所有火车站位置后,返回 best_location

Python3代码(通过豆包Marscode测试)

def solution(n, m, citizens, locations):
    # 初始化最小距离为一个很大的值
    min_total_distance = float('inf')
    # 初始化最优位置为 [-1, -1]
    best_location = [-1, -1]
    
    # 遍历所有火车站位置
    for loc in locations:
        total_distance = 0
        # 计算当前位置到所有市民的总距离
        for citizen in citizens:
            # 计算曼哈顿距离
            distance = abs(loc[0] - citizen[0]) + abs(loc[1] - citizen[1])
            total_distance += distance
        
        # 如果当前总距离小于最小总距离,更新最小总距离和最优位置
        if total_distance < min_total_distance:
            min_total_distance = total_distance
            best_location = loc
    
    return best_location

关键步骤

  1. 初始化最小距离和最优位置:使用 float('inf') 初始化最小距离,使用 [-1, -1] 初始化最优位置。
  2. 遍历所有火车站位置:使用 for loc in locations 遍历每个火车站位置。
  3. 计算当前位置到所有市民的总距离:使用 for citizen in citizens 遍历每个市民,计算曼哈顿距离并累加到 total_distance
  4. 更新最小总距离和最优位置:如果当前总距离小于最小总距离,更新最小总距离和最优位置。

时间复杂度

当前代码的主要时间复杂度来自于两个嵌套的循环:

  1. 外层循环:遍历所有的火车站位置,假设有 M 个火车站位置。
  2. 内层循环:对于每个火车站位置,遍历所有的市民,假设有 N 个市民。

因此,总的时间复杂度为 O(M * N),其中 M 是火车站位置的数量,N 是市民的数量。

空间复杂度

当前代码的空间复杂度主要来自于以下几个方面:

  1. 输入数据citizens 和 locations 列表,假设 citizens 列表的大小为 Nlocations 列表的大小为 M
  2. 变量min_total_distancebest_locationtotal_distance 等变量,这些变量占用的空间是常数级别的。

因此,总的空间复杂度为 O(N + M),其中 N 是市民的数量,M 是火车站位置的数量。

总结

  • 时间复杂度O(M * N)
  • 空间复杂度O(N + M)

心得体会

在解答这道题时,需要注意以下几点:

  1. 曼哈顿距离的计算:确保使用 |x1 - x2| + |y1 - y2| 公式正确计算曼哈顿距离,避免使用其他距离计算方法。
  2. 遍历所有火车站位置:需要遍历所有可能的火车站位置,计算每个位置到所有市民的总距离,确保每个位置都被正确计算。
  3. 更新最优位置:在遍历过程中,如果发现某个位置的总距离小于当前的最小总距离,及时更新最小总距离和最优位置。
  4. 初始化变量:初始化最小总距离为一个很大的值(例如 float('inf')),初始化最优位置为一个无效值(例如 [-1, -1]),以确保在第一次比较时能够正确更新。
  5. 返回结果:遍历完所有火车站位置后,返回最优位置。
  6. 边界条件:确保代码能够处理边界条件,例如只有一个市民或一个火车站位置,以及所有市民和火车站位置都在同一行或同一列的情况。

通过遵循这些注意事项,可以确保代码正确计算最优火车站位置,并处理各种边界情况。