Medium
题目描述
你有一个 m x n 的二维网格 grid,代表一个箱子,同时你有 n 颗球。箱子的顶部和底部都是开着的。
箱子中的每个单元格都有一个对角线挡板,跨越两个角,可以将球导向左侧或者右侧。
- 将球导向右侧的挡板跨越左上角和右下角,在网格中用
1表示。 - 将球导向左侧的挡板跨越右上角和左下角,在网格中用
-1表示。
在箱子每一列的顶端各放一颗球。每颗球都可能卡在箱子里或从底部掉出来。如果球恰好卡在两块挡板之间的 “V” 形图案,或者被挡板导向到箱子的任意一侧边上,就会卡住。
返回一个大小为 n 的数组 answer,其中 answer[i] 是球放在顶部的第 i 列后从底部掉出来的那一列对应的下标,如果球卡在盒子里,则为 -1。
示例 1:
输入: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]]
输出:[1,-1,-1,-1,-1]
解释:这个示例如图所示。
示例 2:
输入:grid = [[-1]]
输出:[-1]
解释:球被卡在左侧边上。
示例 3:
输入: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]]
输出:[0,1,2,3,4,-1]
提示:
m == grid.lengthn == grid[i].length1 <= m, n <= 100grid[i][j]是1或-1
解题思路
这是一道经典的网格模拟题,需要模拟球的下落过程。
核心思路:
- 对于每颗球,从顶部开始逐行模拟下落过程
- 球的移动规律:如果当前位置是
1,球向右下移动;如果是-1,球向左下移动 - 球被卡住的两种情况:
- 撞到边界:向左移动时已在最左列,或向右移动时已在最右列
- 形成 “V” 形:当前格子和下一格子的挡板方向相反(如当前是
1下一个是-1,或当前是-1下一个是1)
算法步骤:
- 遍历每一列,模拟从该列投球
- 对于每颗球,从第 0 行开始,逐行计算球的位置
- 每次移动前检查是否会被卡住:边界检查和 “V” 形检查
- 如果能顺利到达底部,记录最终列位置;否则返回 -1
时间复杂度为 O(m×n),空间复杂度为 O(1)(不含输出数组)。
代码实现
class Solution {
public:
vector<int> findBall(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[0].size();
vector<int> result(n);
for (int col = 0; col < n; col++) {
int currentCol = col;
for (int row = 0; row < m; row++) {
int direction = grid[row][currentCol];
int nextCol = currentCol + direction;
// 检查边界
if (nextCol < 0 || nextCol >= n) {
currentCol = -1;
break;
}
// 检查是否形成 V 形(被卡住)
if (grid[row][nextCol] != direction) {
currentCol = -1;
break;
}
currentCol = nextCol;
}
result[col] = currentCol;
}
return result;
}
};
class Solution:
def findBall(self, grid: List[List[int]]) -> List[int]:
m, n = len(grid), len(grid[0])
result = []
for col in range(n):
current_col = col
for row in range(m):
direction = grid[row][current_col]
next_col = current_col + direction
# 检查边界
if next_col < 0 or next_col >= n:
current_col = -1
break
# 检查是否形成 V 形(被卡住)
if grid[row][next_col] != direction:
current_col = -1
break
current_col = next_col
result.append(current_col)
return result
public class Solution {
public int[] FindBall(int[][] grid) {
int m = grid.Length, n = grid[0].Length;
int[] result = new int[n];
for (int col = 0; col < n; col++) {
int currentCol = col;
for (int row = 0; row < m; row++) {
int direction = grid[row][currentCol];
int nextCol = currentCol + direction;
// 检查边界
if (nextCol < 0 || nextCol >= n) {
currentCol = -1;
break;
}
// 检查是否形成 V 形(被卡住)
if (grid[row][nextCol] != direction) {
currentCol = -1;
break;
}
currentCol = nextCol;
}
result[col] = currentCol;
}
return result;
}
}
var findBall = function(grid) {
const m = grid.length, n = grid[0].length;
const result = [];
for (let col = 0; col < n; col++) {
let currentCol = col;
for (let row = 0; row < m; row++) {
const direction = grid[row][currentCol];
const nextCol = currentCol + direction;
// 检查边界
if (nextCol < 0 || nextCol >= n) {
currentCol = -1;
break;
}
// 检查是否形成 V 形(被卡住)
if (grid[row][nextCol] !== direction) {
currentCol = -1;
break;
}
currentCol = nextCol;
}
result.push(currentCol);
}
return result;
};
复杂度分析
| 复杂度 | 分析 |
|---|---|
| 时间复杂度 | O(m×n),其中 m 是网格的行数,n 是网格的列数。需要对每一列模拟球的下落过程,每次模拟最多经过 m 行 |
| 空间复杂度 | O(1),除了输出数组外,只使用了常数级别的额外空间 |