剑指offer 12 矩阵中的路径 & 剑指offer 13 机器人的运动范围

博客围绕矩阵中的路径和机器人运动轨迹两个二维数组题目展开。对于矩阵路径,用回溯法判断是否存在包含某字符串的路径;对于机器人轨迹,同样用回溯法求其能到达的格子数。指出二维数组题目可考虑用回溯法,且适合用递归实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

矩阵中的路径

题目链接:

请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如 [ a b c e s f c s a d e e ] \begin{bmatrix} a & b & c &e \\ s & f & c & s \\ a & d & e & e\end{bmatrix} asabfdcceese 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。

思路

首先在矩阵中任选一个格子作为路径的起点,假设矩阵中某个格子的字符为ch,并且这个格子将对应于路径上的第i个字符,如果路径上第i字符不是ch,那么这个格子不可能处于路径上的第i个位置,如果路径上的第i个位置正好ch,那么到相邻的格子寻找路径上的第i+1个字符,除矩阵边界上的格子之外,其他格子都有4个相邻的格子,重复这个过程,直到路径上的所有字符都在矩阵中找到相应的位置

使用回溯法来解决这个问题,路径可以被看成一个栈,当在矩阵中定位了路径上的前n个字符的位置后,在与第n个字符对应的格子周围都没有找到n+1个字符,则返回路径上的n-1个字符,重新定位第n个字符,回溯的实现使用递归来实现同时还需要创建一个和矩阵一样大小的boolean类型的矩阵用来标记是否已经访问过这个位置

实现


    public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
    {
    // 创建访问过的路径标记
        boolean[] viested = new boolean[matrix.length];
        // 寻找匹配的开始
        for (int row = 0; row < rows; row++) {
            for (int col = 0; col < cols; col++) {
                if(dfs(matrix, row, rows, col, cols, str, 0, viested)) return true;
            }
        }
        return false;
    }
    
    // 继续寻找匹配的字符串
    public boolean dfs(char[] matrix, int row, int rows, int col, int cols, char[] str, int len, boolean[] viested) {
    // bad case 返回
        if (row < 0 || row >= rows || col < 0 || col >= cols || str[len] != matrix[row * cols + col] || viested[row * cols + col])
            return false;
            
        // 及时返回 到最后了就证明OK了 返回  找了最后一位
        if (len == str.length -1 ) return true;
        // 设置已经访问过了
        viested[row * cols + col] = true;

        // 递归访问一个节点的四周的四个节点 
        boolean isExit =  dfs(matrix, row + 1, rows, col, cols, str, len + 1, viested) ||
                dfs(matrix, row - 1, rows, col, cols, str, len + 1, viested) ||
                dfs(matrix, row, rows, col + 1, cols, str, len + 1, viested) ||
                dfs(matrix, row, rows, col - 1, cols, str, len + 1, viested);
        
        // 遍历结束后恢复已经访问的标记 
        viested[row * cols + col] = false;
        
        return isExit;
    }
    

机器人运动轨迹

题目路径

题目描述:

地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?

思路

这个题和上一个题目很类似也可以使用回溯的方法来解决,但是这两个题目有略微的不同,不同点在于上一个题目是在二维数组中查找路径,没有规定起点,但是这道题目规定了开始的位置,同时两个题目的终止条件不同,上一个题目是查找是否存在路径,这个题目是求用几个满足条件的解。

从矩阵的(0,0) 开始遍历二维矩阵,同时创建一个boolean数组标记是否已经访问过了相应的位置,开始递归的遍历这个不许要查找的时候后头去找,于是不需要想上一个题目一样返回去更改boolean数组,编写计算位数之和的函数判断是否超过了给定的K值,于是代码实现如下和上一面的一题类似但是有些许的不同。

实现

  public int movingCount(int threshold, int rows, int cols) {
        boolean[] visited = new boolean[rows * cols];
        return dfs(threshold, 0, rows, 0, cols, visited);
        
    }
    
    public int dfs(int threshold, int row, int rows, int col, int cols, boolean[] visited) {
        if (row < 0 || row >= rows || col < 0 || col >= cols || visited[row * cols + col] || cal(row, col) > threshold) return 0;
        visited[row * cols + col] = true;
        return dfs(threshold, row + 1, rows, col, cols, visited) + 
               dfs(threshold, row - 1, rows, col, cols, visited) + 
               dfs(threshold, row, rows, col + 1, cols, visited) + 
               dfs(threshold, row, rows, col - 1, cols, visited) + 1;
    }
    
    public int cal(int row, int col) {
        int rowSum = 0;
        int colSum = 0;
        while (row > 0) {
            rowSum += row % 10;
            row = row/10;
        }
        while (col > 0) {
            colSum += col % 10;
            col /= 10;
        }
        return rowSum + colSum;
    }

总结

对面题目为二维数组的题目可以思考下能否用相似的回溯方法解决,通常回溯法适合用递归的代码实现,当我们到达某一个节点适合,尝试所有可能的选项并在满足条件的前提下递归的达到下一个节点。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值