LeetCode 1706. 球会落何处 一题多解

1706. 球会落何处题解

题目来源:1706. 球会落何处

2022.02.24 每日一题

每日一题专栏地址:LeetCode 每日一题题解更新中❤️💕

今天的题目就比较容易了,更完题解接着收拾行李去了,明天就要返校了,希望明天是个easy`,嘿嘿

今天的题目比较容易理解,就是模拟小球的行走路径

我们可以把小球的行走路径进行拆分,从图中AB会发现小球的行走分为三个部分

请添加图片描述

因此,在一层之中我们只需要统计 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的方法啦,

首先我们要找出什么情况下小球回卡住

一共分为四种情况,分别为图片中CDEF 四种情况

抛除去这四种情况,小球回更改自己 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][jgrid[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,还请见谅),还请大佬们指教

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值