本文整理了 3 道 Snowflake OA 编程题,分别涉及有序数组中的最小连接代价、带障碍物的网格路径优化,以及带时间约束的最大收益问题。三道题分别考察前缀和与预处理、二分答案结合 BFS,以及离散化与动态规划。下面按题目顺序整理题目要求和解题思路,方便准备 Snowflake OA 的同学复习相关算法。
Task 1:有序数组的最小连接代价
题目描述
给定一个升序排列的数组 a,数组中的每个元素代表一个服务器的位置。
对于相邻的两个位置 i 和 i + 1,将它们连接起来的代价为:
a[i + 1] - a[i]
此外,每个服务器还可以连接到距离自己最近的相邻服务器,连接代价只需 1。
给定若干次查询,需要计算指定区间内的最小连接代价。
解题思路
这道题的关键是预处理,避免在每次查询时重复计算。
由于数组已经升序排列,可以分别预处理两个方向的连接代价:
-
从左向右: 计算每个服务器连接右侧服务器时的最小代价。
-
从右向左: 计算每个服务器连接左侧服务器时的最小代价。
接着,分别构建两个方向的前缀和数组,累计对应的连接代价。
对于每次区间查询,可以根据查询的方向选择对应的前缀和,通过前缀和之差快速计算区间内的总代价。
这样就能将重复计算转化为一次预处理和高效的区间查询。
Task 2:带障碍物的网格最大安全路径
题目描述
给定一个大小为 n × m 的网格,其中部分格子为障碍物。每次只能向上、下、左、右四个方向移动,需要从左上角 (1, 1) 到达右下角 (n, m)。
一条路径的安全值定义为:路径上所有格子到所有障碍物的曼哈顿距离中的最小值。
曼哈顿距离定义为:
|x1 - x2| + |y1 - y2|
需要找到安全值最大的路径,并返回该路径的最短步数。
解题思路
这道题可以使用 二分答案 + BFS。
首先,预处理每个格子到最近障碍物的曼哈顿距离。对于每个格子,这个距离决定了它能够满足的最大安全值。
接着,对路径的安全值进行二分。假设当前尝试的安全值为 lim,那么只有安全值不小于 lim 的格子才能被访问。
每次二分检查时,从起点执行 BFS,只允许进入满足距离条件的格子,判断能否到达终点。
-
如果能够到达终点,说明安全值至少为
lim的路径存在,可以尝试更大的安全值。 -
如果无法到达终点,则需要降低安全值。
当二分结束后,就能确定最大的可行安全值。由于题目还要求返回该安全值下的最短路径步数,可以在最终确定的阈值下再次执行 BFS,计算从起点到终点的最短距离。
Task 3:带时间约束的最大收益
题目描述
给定 n 个事件,每个事件包含三个属性:
-
start[i]:事件的开始时间。 -
dur[i]:事件持续的时间。 -
vol[i]:完成事件可以获得的收益。
每个事件的结束时间为 start[i] + dur[i]。
同一时间只能参与一个事件,不能选择时间上相互冲突的事件。请计算能够获得的最大总收益。
解题思路
这道题可以使用 动态规划 + 坐标离散化 + 二分查找。
如果直接按照时间建立 DP 数组,当时间范围很大时,会浪费大量空间。因此,可以将所有事件的开始时间和结束时间收集起来,排序并去重,将原始时间映射为离散下标。
定义 dp[i] 为处理到离散时间点 i 时,能够获得的最大收益。
对于每个事件,设其开始时间为 s,结束时间为 e,收益为 v。处理该事件时,需要考虑两种情况:
-
不参加当前事件: 沿用前一个时间点的最大收益,即
dp[i] = dp[i - 1]。 -
参加当前事件: 在当前事件开始前,找到最后一个与当前事件不冲突的时间点,从该时间点继承最大收益,再加上当前事件的收益。
因此,状态转移的核心是:
dp[e] = max(dp[e], dp[p] + v)
其中,p 表示当前事件开始前,最后一个允许接续的离散时间点。由于事件时间可能很大,可以通过二分查找确定这个位置。
处理完所有事件后,DP 数组中的最大可行收益就是答案。
需要注意,实际实现时应先按事件结束时间排序,并明确允许前一事件结束时间等于后一事件开始时间时的二分边界。这样才能正确处理首尾相接的事件。
总结
这组三道 Snowflake OA 真题覆盖了几种常见的算法组合:
-
前缀和与预处理: 将重复的区间计算转化为快速查询。
-
二分答案与 BFS: 将路径优化问题转化为可行性判断。
-
动态规划、离散化与二分查找: 在较大的时间范围内计算不重叠事件的最大收益。
准备 Snowflake OA 时,除了掌握单个算法,还需要关注多个算法之间的组合方式,尤其是如何利用预处理减少重复计算,以及如何通过二分查找优化 DP 状态转移。