解题博客:LeetCode 1706. 球会落何处
问题描述
我们有一个大小为 m x n
的二维网格 grid
,它表示一个箱子。每一列的顶部都放有一颗球。每个格子中有一个斜向的挡板,可以将球导向左侧或右侧。球的移动规则如下:
1
表示将球导向右侧。-1
表示将球导向左侧。
在箱子的顶部每一列放置一颗球,球会向下移动,并可能被卡在箱子里。球可能在底部掉出,也可能被卡住。球卡住的情况:
- 当球在两个挡板之间形成 "V" 形状时会被卡住;
- 球可能会被导向箱子的左右边界而卡住。
我们的任务是模拟每颗球的移动,判断每颗球最终会从哪个列的底部掉出,或者是否会被卡住。结果应该是一个大小为 n
的数组 answer
,其中每个元素表示球从对应列顶部开始的最终落点。如果球被卡住,则返回 -1
。
示例
示例 1
输入:
python
grid = [
[1, 1, 1, -1, -1],
[1, 1, 1, -1, -1],
[-1, -1, -1, 1, 1],
[1, 1, 1, 1, -1],
[-1, -1, -1, -1, -1]
]
输出:
python
[1, -1, -1, -1, -1]
解释:
- 球 b0 从第 0 列掉出,从第 1 列出来;
- 球 b1 被卡在第 1 行、第 2 列和第 3 列之间的 "V" 形里,无法掉出,结果是
-1
; - 其他球也因为类似的原因无法掉出。
示例 2
输入:
python
grid = [[-1]]
输出:
python
[-1]
解释:球从顶部掉落后被卡在了箱子的左边界。
示例 3
输入:
python
grid = [
[1, 1, 1, 1, 1, 1],
[-1, -1, -1, -1, -1, -1],
[1, 1, 1, 1, 1, 1],
[-1, -1, -1, -1, -1, -1]
]
输出:
python
[0, 1, 2, 3, 4, -1]
解释:
- 球从每一列开始依次掉落,最终除了第 5 列外,其他球都成功掉出。
解题思路
为了模拟每颗球的移动,我们可以逐列模拟球的下落过程。每颗球从顶部的某一列开始,并根据当前格子的值判断球的移动方向。如果球被导向左侧或右侧,我们继续向下遍历并检查下一个格子,直到球最终被卡住或者成功掉落。
步骤
- 初始化: 我们维护一个大小为
n
的数组ans
,每个位置初始化为-1
,表示所有球都尚未掉落。 - 逐列模拟: 对于每列,我们模拟球的下落过程。球从每列顶部出发,根据当前格子的值(
1
或-1
)决定球向左或向右移动。 - 判断卡住: 如果球在某一格后超出边界(即小于 0 或大于等于
n
),或者球被卡在 "V" 形结构中(即当前格子的值与下一格的值方向相反),我们就认为球卡住,直接跳出循环。 - 记录结果: 如果球成功通过所有行并最终落在某个列上,我们记录下该列的下标。
代码实现
python
class Solution:
def findBall(self, grid: List[List[int]]) -> List[int]:
n = len(grid[0]) # 获取列数
ans = [-1] * n # 初始化答案数组,-1 表示球被卡住
for j in range(n): # 对每列进行模拟
cur = j # 当前球的列
for row in grid: # 遍历每一行
d = row[cur] # 获取当前格子的值,-1 或 1
cur += d # 根据值决定球的方向
# 如果球出界,或者球卡在 V 形结构中,则提前结束
if cur < 0 or cur >= n or row[cur] != d:
break
else:
# 如果没有提前结束,说明球成功掉出
ans[j] = cur
return ans
代码解释
-
初始化:
n = len(grid[0])
:获取网格的列数n
。ans = [-1] * n
:初始化答案数组,所有球都假设会卡住。
-
模拟每列球的移动:
for j in range(n):
:对于每列,从顶部开始模拟球的下落。cur = j
:当前球位于第j
列。
-
遍历每一行:
d = row[cur]
:获取当前格子的值,1
或-1
,决定球的移动方向。cur += d
:球根据当前格子的值移动到下一列。if cur < 0 or cur >= n or row[cur] != d:
:判断球是否出界或卡住。
-
记录结果:
- 如果球没有被卡住,最终会通过所有行,我们将其最终落点记录在
ans[j]
中。
- 如果球没有被卡住,最终会通过所有行,我们将其最终落点记录在
-
返回结果:
- 返回
ans
数组,表示每颗球最终的位置或是否卡住。
先列后行,如果同一行内的两次行动不是相同的,即不是都在左或者都在右边,就是V形状,否则是互通的。如果没有V形状,或者到达边界那么,可以记录这里的else是相对于for而言,如果for循环没有break就会记录
- 返回
复杂度分析
- 时间复杂度:
O(mn)
,其中m
是网格的行数,n
是网格的列数。我们需要模拟每个球的下落过程,最多遍历m
行,对于每个球最多遍历一次n
列。 - 空间复杂度:
O(n)
,我们需要一个大小为n
的数组ans
来存储每颗球的最终位置。
总结
这道题目主要考察模拟和判断的能力,通过逐列模拟每颗球的下落过程,判断球是否会卡住,并记录球最终的落点。通过使用简单的循环和条件判断,我们能够高效地解决这个问题。