当前位置: 首页 > news >正文

LeetCode 317 最短距离选址问题详解(Swift 实现 + BFS 多源遍历)

在这里插入图片描述
在这里插入图片描述

文章目录

    • 摘要
    • 描述
      • 示例 1:
    • 题解答案
      • 遍历方式:
    • 题解代码分析(Swift 实现)
    • 题解代码解析
      • 核心结构
      • 遍历每一栋建筑
      • BFS 细节逻辑
      • 最后从所有“被所有建筑都访问过的空地”中选出最小距离:
    • 示例测试及结果
    • 时间复杂度
    • 空间复杂度
    • 总结
      • 实际应用场景:

摘要

如果你在城市规划系统里工作,或者搞一个模拟经营类游戏,那你肯定遇到过这样的需求:找一个最优位置建房子,让它到所有已有建筑的总距离最短

LeetCode 317 就是这么一道“建房选址”的题,表面是 BFS 遍历地图,实际是一个网格图上的多源路径搜索 + 最小和策略的组合题。

这篇文章用 Swift 带你分析如何高效地选出“最适合造房子”的格子位置,既有运行逻辑讲解,也有完整 Demo 和测试案例,适合用来刷题、面试、或做模拟业务模型的参考。

描述

题目是这样说的:

给你一个 m x n 的网格地图 grid,每个格子可能是:

  • 0:空地,可以建房子
  • 1:建筑,不能通过
  • 2:障碍物,不能通过

你需要从这些空地中选一个点建房子,要求:

该点到所有建筑的曼哈顿距离之和最小

如果不存在这样的位置可以访问所有建筑,则返回 -1

示例 1:

输入:
[[1,0,2,0,1],[0,0,0,0,0],[0,0,1,0,0]]输出:
7解释:
选中 [1,2] 这个位置,到三个建筑的距离是:
(1,2) -> (0,0): 3
(1,2) -> (0,4): 3
(1,2) -> (2,2): 1
总和为 7,是所有可选位置中最小的。

题解答案

为了找出一个“能到所有建筑”的空地,并且使得总路径最短,我们可以反向思考:

遍历方式:

  • 不是从空地出发去看能到哪些建筑。

  • 而是从每一栋建筑出发去 BFS 扫空地,记录每个空地的:

    • 累计路径总和(sumDistance)
    • 被访问建筑数量(reachCount)

最后检查哪些空地被所有建筑都访问到,再从这些里选一个总距离最小的。

题解代码分析(Swift 实现)

func shortestDistance(_ grid: [[Int]]) -> Int {let rows = grid.countlet cols = grid[0].countvar distanceSum = Array(repeating: Array(repeating: 0, count: cols), count: rows)var reachCount = Array(repeating: Array(repeating: 0, count: cols), count: rows)let directions = [(-1,0), (1,0), (0,-1), (0,1)]var totalBuildings = 0for i in 0..<rows {for j in 0..<cols {if grid[i][j] == 1 {totalBuildings += 1bfs(i, j, grid, &distanceSum, &reachCount, rows, cols, directions)}}}var minDist = Int.maxfor i in 0..<rows {for j in 0..<cols {if grid[i][j] == 0 && reachCount[i][j] == totalBuildings {minDist = min(minDist, distanceSum[i][j])}}}return minDist == Int.max ? -1 : minDist
}func bfs(_ row: Int, _ col: Int, _ grid: [[Int]],_ distanceSum: inout [[Int]],_ reachCount: inout [[Int]],_ rows: Int, _ cols: Int,_ directions: [(Int, Int)]) {var visited = Array(repeating: Array(repeating: false, count: cols), count: rows)var queue: [(Int, Int, Int)] = [(row, col, 0)]visited[row][col] = truewhile !queue.isEmpty {let (x, y, dist) = queue.removeFirst()for (dx, dy) in directions {let newX = x + dxlet newY = y + dyif newX >= 0, newX < rows, newY >= 0, newY < cols,!visited[newX][newY], grid[newX][newY] == 0 {visited[newX][newY] = truedistanceSum[newX][newY] += dist + 1reachCount[newX][newY] += 1queue.append((newX, newY, dist + 1))}}}
}

题解代码解析

核心结构

  • distanceSum[i][j]: 表示空地 (i, j) 到所有建筑的距离之和;
  • reachCount[i][j]: 表示这个空地目前能被多少个建筑访问到;
  • bfs():从每一栋建筑出发,把可以走到的空地进行更新。

遍历每一栋建筑

if grid[i][j] == 1 {bfs(i, j, ...)
}

每次都从建筑出发跑一轮 BFS,让这栋建筑“把它能访问的空地都更新一遍”。

BFS 细节逻辑

  • 维护一个 visited 数组防止重复遍历;

  • 遇到空地就:

    • 更新它的 distanceSum 累加路径长度;
    • 更新它的 reachCount 加 1;
    • 加入下一轮队列。

最后从所有“被所有建筑都访问过的空地”中选出最小距离:

if reachCount[i][j] == totalBuildings

这句话的意思是,这块空地被所有建筑都走到过,才是合法候选地。

示例测试及结果

我们来验证下主例题:

let input = [[1, 0, 2, 0, 1],[0, 0, 0, 0, 0],[0, 0, 1, 0, 0]
]
let result = shortestDistance(input)
print(result)  // 输出:7

解释:

选中 [1,2] 位置,离三栋建筑的距离为:3 + 3 + 1 = 7
而其他空地虽然能访问一部分建筑,但总距离更大或不满足“可达所有建筑”的条件。

时间复杂度

  • 对于每个建筑(共 b 个),执行一次 BFS;
  • 每次 BFS 最多遍历所有空地(最多 m * n 个);

所以总时间复杂度是 O(b × m × n),对于题目给定的规模是可以接受的。

空间复杂度

  • distanceSumreachCountvisited 都是 m x n 的二维数组;
  • 每次 BFS 使用的队列空间也最多为 O(mn)

所以整体空间复杂度为 O(m × n)

总结

LeetCode 317 是一道典型的“网格图上多源最短路径累加”问题,技巧核心是:

  • 多次从“源点”出发进行 BFS;
  • 用额外数组记录“累加状态”和“覆盖次数”;
  • 最后从所有可选项中选最优解。

实际应用场景:

  • 城市交通:选择公交站点或医院位置;
  • 游戏地图:找玩家基地或资源点的最优投放位置;
  • 后端服务部署:计算请求源覆盖范围、延迟等指标汇总选址;
http://www.xdnf.cn/news/1078921.html

相关文章:

  • 高边驱动 低边驱动
  • 多模态AI Agent技术栈解析:视觉-语言-决策融合的算法原理与实践
  • Kafka生态整合深度解析:构建现代化数据架构的核心枢纽
  • JA3指纹在Web服务器或WAF中集成方案
  • 专题:2025即时零售与各类人群消费行为洞察报告|附400+份报告PDF、原数据表汇总下载
  • MacOS Safari 如何打开F12 开发者工具 Developer Tools
  • 打造一个可维护、可复用的前端权限控制方案(含完整Demo)
  • 请求未达服务端?iOS端HTTPS链路异常的多工具抓包排查记录
  • 【CSS揭秘】笔记
  • 网络基础(3)
  • HTML初学者第二天
  • 利用tcp转发搭建私有云笔记
  • Chart.js 安装使用教程
  • 【强化学习】深度解析 GRPO:从原理到实践的全攻略
  • 怎样理解:source ~/.bash_profile
  • vscode vim插件示例json意义
  • 电子电气架构 --- SOVD功能简单介绍
  • 如何系统性评估运维自动化覆盖率:方法与关注重点
  • Spark流水线数据探查组件
  • 【字节跳动】数据挖掘面试题0002:从转发数据中求原视频用户以及转发的最长深度和二叉排序树指定值
  • 计算机视觉的新浪潮:扩散模型(Diffusion Models)技术剖析与应用前景
  • 六、软件操作手册
  • 【Python】进阶 - 数据结构与算法
  • Python 高光谱分析工具(PyHAT)
  • Python 数据分析:numpy,说人话,说说数组维度。听故事学知识点怎么这么容易?
  • vue中的toRef
  • C#上位机串口接口
  • docker常见命令
  • 模型预测专题:强鲁棒性DPCC
  • Springboot开发常见注解一览