1706. 球会落何处题解
题目来源:1706. 球会落何处
2022.02.24 每日一题
每日一题专栏地址:LeetCode 每日一题题解更新中❤️💕
今天的题目就比较容易了,更完题解接着收拾行李去了,明天就要返校了,希望明天是个
easy`,嘿嘿
今天的题目比较容易理解,就是模拟小球的行走路径
我们可以把小球的行走路径进行拆分,从图中A
到B
会发现小球的行走分为三个部分
因此,在一层之中我们只需要统计 col
的变化即可
法一:模拟法
首先是模拟方法,即简简单单模拟,更改小球的 col
的值即可
class Solution {
public:
int m, n;
vector<int> findBall(vector<vector<int>> &grid) {
// 统计给定数组的长与宽
m = grid.size(), n = grid[0].size();
// 提前给出结果数组
vector<int> res(n, -1);
// 模拟遍历各个小球的行动路线
for (int i = 0; i < n; i++) {
// 首先定义一个变量,用来标志小球的位置
int col = i;
// 遍历各行对应的位置
for (vector<int> row: grid) {
int temp = row[col];
// 更新小球的位置
col += row[col];
// 如果小球的位置更新后,在数组之外,证明小球被卡在了边框
// 如果小球的两次前后变化的位置的值不相等,则说明,小球被卡在了一个 V 之中
if (col < 0 || col >= n || temp != row[col]) {
// 证明小球已经被卡住,无法继续下潜
col = -1;
break;
}
}
// 如果小球最后的坐标不为 -1 ,则证明小球成功出逃,更新结果数组中的值
if (col >= 0) {
res[i] = col;
}
}
return res;
}
};
class Solution {
int m, n;
public int[] findBall(int[][] grid) {
// 统计给定数组的长与宽
m = grid.length;
n = grid[0].length;
// 提前给出结果数组
int[] res = new int[n];
Arrays.fill(res, -1);
// 模拟遍历各个小球的行动路线
for (int i = 0; i < n; i++) {
// 首先定义一个变量,用来标志小球的位置
int col = i;
// 遍历各行对应的位置
for (int[] row : grid) {
int temp = row[col];
// 更新小球的位置
col += row[col];
// 如果小球的位置更新后,在数组之外,证明小球被卡在了边框
// 如果小球的两次前后变化的位置的值不相等,则说明,小球被卡在了一个 V 之中
if (col < 0 || col >= n || temp != row[col]) {
// 证明小球已经被卡住,无法继续下潜
col = -1;
break;
}
}
// 如果小球最后的坐标不为 -1 ,则证明小球成功出逃,更新结果数组中的值
if (col >= 0) {
res[i] = col;
}
}
return res;
}
}
法二:DFS
接下来就是DFS
的方法啦,
首先我们要找出什么情况下小球回卡住
一共分为四种情况,分别为图片中C
、D
、E
、F
四种情况
抛除去这四种情况,小球回更改自己 col
的位置,并且 row
的值会增 1
结束的条件,要么
小球被卡住、要么
row 的值最后比 m 的值要大
那么就简单了,上代码
class Solution {
public:
int m, n;
vector<vector<int>> grid;
vector<int> findBall(vector<vector<int>> &grid) {
// 统计给定数组的长与宽
m = grid.size(), n = grid[0].size();
this->grid = grid;
// 定义结果数组
vector<int> res;
// 遍历小球,进行递归操作
for (int i = 0; i < n; i++) {
res.push_back(dfs(0, i));
}
return res;
}
int dfs(int i, int j) {
// 模拟 E、F 两种被卡住的情况
if ((j == n - 1 && grid[i][j] == 1) || (j == 0 && grid[i][j] == -1))
return -1;
// 模拟小球被 V 型卡住的情况
if (grid[i][j]!=grid[i][j+grid[i][j]])
return -1;
// 如果以及在最底层,则只需更新小球的位置即可(即步骤 3)
if (i == m - 1)
return j + grid[i][j];
// 如果不满足意思条件,说明小球还在下落,则继续进行递归
return dfs(i + 1, j + grid[i][j]);
}
};
class Solution {
int m, n;
int[][] grid;
int[] findBall(int[][] grid) {
// 统计给定数组的长与宽
m = grid.length;
n = grid[0].length;
this.grid = grid;
// 定义结果数组
int[] res = new int[n];
// 遍历小球,进行递归操作
for (int i = 0; i < n; i++) {
res[i] = dfs(0, i);
}
return res;
}
int dfs(int i, int j) {
// 模拟 E、F 两种被卡住的情况
if ((j == n - 1 && grid[i][j] == 1) || (j == 0 && grid[i][j] == -1)) return -1;
// 模拟小球被 V 型卡住的情况
if (grid[i][j] != grid[i][j + grid[i][j]]) return -1;
// 如果以及在最底层,则只需更新小球的位置即可(即步骤 3)
if (i == m - 1) return j + grid[i][j];
// 如果不满足意思条件,说明小球还在下落,则继续进行递归
return dfs(i + 1, j + grid[i][j]);
}
}
法三:动态规划
最后是动态规划的方法
刚才递归的时候,我们可以发现这样一个规律 g r i d [ i ] [ j ] = = g r i d [ i ] [ j + g r i d [ i ] [ j ] ] grid[i][j]==grid[i][j+grid[i][j]] grid[i][j]==grid[i][j+grid[i][j]]
我们的问题是判断小球最后能从哪个通道掉出来
让我们换一个思路
每个出口可以掉出哪些小球
我们将公式转换一下 g r i d [ i ] [ j − g r i d [ i ] [ j ] ] = = g r i d [ i ] [ j ] grid[i][j-grid[i][j]]==grid[i][j] grid[i][j−grid[i][j]]==grid[i][j]
从出口向上进行查找入口,无法查找到入口的小球就是会被卡在途中的小球(-1)
直接上代码
class Solution {
public:
vector<int> findBall(vector<vector<int>> &grid) {
int m, n;
// 统计给定数组的长与宽
m = grid.size(), n = grid[0].size();
// 创建标记数组,res[0] 就是小球最初始的状态,默认值赋为 -1,默认无法到达出口
vector<vector<int>> res(m + 1, vector<int>(n, -1));
// 赋予动态规划的初始值
// 在出口的格子的值就是出口所在的 col
for (int i = 0; i < n; i++) res[m][i] = i;
// 进行 dp
for (int row = m - 1; row >= 0; row--)
for (int col = 0; col < n; col++) {
// 如果不在这个范围 n 之中则说明小球已经被卡住了
if (col - grid[row][col] < 0 || col - grid[row][col] >= n) continue;
if (grid[row][col] == grid[row][col - grid[row][col]])
res[row][col - grid[row][col]] = res[row + 1][col];
}
return res[0];
}
};
class Solution {
public int[] findBall(int[][] grid) {
int m, n;
// 统计给定数组的长与宽
m = grid.length;
n = grid[0].length;
// 创建标记数组,res[0] 就是小球最初始的状态,默认值赋为 -1,默认无法到达出口
int[][] res = new int[m + 1][n];
for (int i = 0; i < m + 1; i++)
for (int j = 0; j < n; j++)
res[i][j] = -1;
// 赋予动态规划的初始值
// 在出口的格子的值就是出口所在的 col
for (int i = 0; i < n; i++) res[m][i] = i;
// 进行 dp
for (int row = m - 1; row >= 0; row--)
for (int col = 0; col < n; col++) {
// 如果不在这个范围 n 之中则说明小球已经被卡住了
if (col - grid[row][col] < 0 || col - grid[row][col] >= n) continue;
if (grid[row][col] == grid[row][col - grid[row][col]])
res[row][col - grid[row][col]] = res[row + 1][col];
}
return res[0];
}
}
注:Java填充二维数组我不知道还有没有更好的方法(刚开始自学Java,还请见谅),还请大佬们指教